Universidad Universidad Nacional del Oeste
Carrera Esp. en Ciencia de Datos
Materia Fundamentos de Estadísticas (01050)
Profesora Mg. Sc. Silvia N. Pérez
Grupo Nº 3
Alumnos {Lic. Leticia Sosa, Ing. Federico Czerniawski, Mg. Pablo Pandolfo}
Fecha Junio 2025



Librerias usadas

library(readxl)
library(dplyr)
library(ggplot2)
library(ggthemes)
library(hrbrthemes)
library(plotly)
library(tidyr)
library(tidyverse)
library(scales)
library(corrplot)
library(car)
library(nortest)
library(tseries)
library(knitr)
library(vcd)



Importación de la base de datos

# Borramos ambiente de trabajo
rm(list = ls())
# Seteamos directorio de trabajo
setwd("/Users/ppando/Materias/data/materias/estadistica/tp_grupal")
# Cargamos datos del archivo
datos <- read_xlsx("seguros.xlsx")
# Mostramos los primeros 6 casos
head(datos)



Parte 1: análisis exploratorio


a. Identificar el tipo de cada una de las variables registradas (cuali, cuanti)

# Mostramos estructura de los datos
str(datos)
## tibble [669 × 7] (S3: tbl_df/tbl/data.frame)
##  $ Edad   : num [1:669] 18 37 29 54 19 30 63 24 27 59 ...
##  $ Genero : chr [1:669] "masculino" "femenino" "femenino" "femenino" ...
##  $ IMC    : num [1:669] 17.3 17.3 38.8 27.6 33.1 ...
##  $ Fuma   : chr [1:669] "si" "no" "no" "no" ...
##  $ Region : chr [1:669] "nordeste" "nordeste" "sureste" "noroeste" ...
##  $ ingreso: num [1:669] 1337 1181 1092 1348 1203 ...
##  $ premio : num [1:669] 40.7 41 39.7 41.7 41.3 ...


  • cualitativas nominales = {Genero, Fuma, Region}
  • cuantitativas:
    • discretas = {Edad}
    • continuas = {IMC, ingreso, premio}


b. Decidir si hay datos faltantes, en cuyo caso eliminar los casos

# Contamos número de nulos por variables (columnas)
sapply(datos, function(x) sum(is.na(x)))
##    Edad  Genero     IMC    Fuma  Region ingreso  premio 
##       0       0       0       1       0       0       0
# Eliminamos casos (filas) con nulos
datos <- datos[!is.na(datos$Fuma),]

# Verificamos que el caso con nulos fue eliminado
sapply(datos, function(x) sum(is.na(x)))
##    Edad  Genero     IMC    Fuma  Region ingreso  premio 
##       0       0       0       0       0       0       0


c. Realizar boxplots para cada variable cuantitativa, separando según la/las variables cualitativas que considere importantes

seguros_long_Genero <- datos %>%
  select(Edad, Genero, IMC, ingreso, premio) %>%
  pivot_longer(cols = -Genero, names_to = "variable", values_to = "valor")

ggplotly(
  ggplot(seguros_long_Genero, aes(x = Genero, y = valor, fill = Genero)) +
    geom_boxplot(alpha = 0.7) +
    facet_wrap(~ variable, scales = "free_y") +  # Un panel por variable
    theme_bw() +
    theme(legend.position = "none") +
    labs(
      title = "Distribución de variables por Genero",
      x = "Género",
      y = "Valor"
    )
)
seguros_long_Fuma <- datos %>%
  select(Edad, IMC, Fuma, ingreso, premio) %>%
  pivot_longer(cols = -Fuma, names_to = "variable", values_to = "valor")

ggplotly(
  ggplot(seguros_long_Fuma, aes(x = Fuma, y = valor, fill = Fuma)) +
    geom_boxplot(alpha = 0.7) +
    facet_wrap(~ variable, scales = "free_y") +  # Un panel por variable
    theme_bw() +
    theme(legend.position = "none") +
    labs(
      title = "Distribución de variables por Condición de Fumador",
      x = "Fuma",
      y = "Valor"
    )
)
seguros_long_Region <- datos %>%
  select(Edad, IMC, Region, ingreso, premio) %>%
  pivot_longer(cols = -Region, names_to = "variable", values_to = "valor")

ggplotly(
  ggplot(seguros_long_Region, aes(x = Region, y = valor, fill = Region)) +
    geom_boxplot(alpha = 0.7) +
    facet_wrap(~ variable, scales = "free_y") +  # Un panel por variable
    theme_bw() +
    theme(legend.position = "none") +
    labs(
      title = "Distribución de variables por Region",
      x = "Región",
      y = "Valor"
    )
)

Se observa que las variables cuantitativas agrupadas por las distintas cualitativas presentan distribuciones similares.

Además, la variable premio presenta un valor muy atípico.


d. Identificar si hay datos muy atípicos, en cuyo caso eliminar los casos

Como se concluye del análisis anterior, la variable premio presenta un valor muy atípico.

Procedemos a eliminarlo.

gplot = datos %>% filter(Genero == "femenino") %>% 
  ggplot(mapping = aes(x=Region, y=premio, color=Fuma)) +
  geom_point() +
  stat_summary(fun ="mean", geom="crossbar", color="red", linewidth=0.5) + # mostramos la media
  theme_bw() + xlab("Region") + ylab("Premio")

ggplotly(gplot)
# Lo eliminamos
datos <- datos %>% filter(premio != max(premio))


e. Hallar las medidas resumen de cada variable cuantitativa, separando según lo hecho en el ítem anterior

# Declaramos a las variables cualitativas como factor, para poder reconocer categorias
datos$Genero <- as.factor(datos$Genero)
datos$Fuma <- as.factor(datos$Fuma)
datos$Region <- as.factor(datos$Region)

# Mostramos medidas resumen
summary(datos)
##       Edad             Genero         IMC        Fuma          Region       ingreso      
##  Min.   :18.00   femenino :321   Min.   :15.96   no:535   nordeste:162   Min.   : 417.7  
##  1st Qu.:27.00   masculino:346   1st Qu.:26.18   si:132   noroeste:165   1st Qu.: 938.6  
##  Median :39.00                   Median :30.21            sureste :168   Median :1087.3  
##  Mean   :39.32                   Mean   :30.47            suroeste:172   Mean   :1100.9  
##  3rd Qu.:51.00                   3rd Qu.:34.43                           3rd Qu.:1263.8  
##  Max.   :64.00                   Max.   :52.58                           Max.   :1756.6  
##      premio     
##  Min.   :32.62  
##  1st Qu.:37.48  
##  Median :38.84  
##  Mean   :38.84  
##  3rd Qu.:40.10  
##  Max.   :44.67
# Volvemos a mostrar graficamente las medidas resumen de las variables cuantis agrupadas por las variables cualis
seguros_long_Genero <- datos %>%
  select(Edad, Genero, IMC, ingreso, premio) %>%
  pivot_longer(cols = -Genero, names_to = "variable", values_to = "valor")

ggplotly(
  ggplot(seguros_long_Genero, aes(x = Genero, y = valor, fill = Genero)) +
    geom_boxplot(alpha = 0.7) +
    facet_wrap(~ variable, scales = "free_y") +  # Un panel por variable
    theme_bw() +
    theme(legend.position = "none") +
    labs(
      title = "Distribución de variables por Genero",
      x = "Género",
      y = "Valor"
    )
)
seguros_long_Fuma <- datos %>%
  select(Edad, IMC, Fuma, ingreso, premio) %>%
  pivot_longer(cols = -Fuma, names_to = "variable", values_to = "valor")

ggplotly(
  ggplot(seguros_long_Fuma, aes(x = Fuma, y = valor, fill = Fuma)) +
    geom_boxplot(alpha = 0.7) +
    facet_wrap(~ variable, scales = "free_y") +  # Un panel por variable
    theme_bw() +
    theme(legend.position = "none") +
    labs(
      title = "Distribución de variables por Condición de Fumador",
      x = "Fuma",
      y = "Valor"
    )
)
seguros_long_Region <- datos %>%
  select(Edad, IMC, Region, ingreso, premio) %>%
  pivot_longer(cols = -Region, names_to = "variable", values_to = "valor")

ggplotly(
  ggplot(seguros_long_Region, aes(x = Region, y = valor, fill = Region)) +
    geom_boxplot(alpha = 0.7) +
    facet_wrap(~ variable, scales = "free_y") +  # Un panel por variable
    theme_bw() +
    theme(legend.position = "none") +
    labs(
      title = "Distribución de variables por Region",
      x = "Región",
      y = "Valor"
    )
)


f. Calcular la correlación entre todos los pares posibles de variables numéricas

# Calculamos la matriz de correlación que nos muestra los coeficientes de correlación entre cada para de variables. 
datos_numericos <- datos %>% select(Edad, IMC, ingreso, premio)
correlaciones <- cor(datos_numericos)
correlaciones
##                Edad        IMC     ingreso     premio
## Edad    1.000000000 0.14973714 0.008118905 0.01590152
## IMC     0.149737140 1.00000000 0.077763646 0.03828891
## ingreso 0.008118905 0.07776365 1.000000000 0.87995085
## premio  0.015901515 0.03828891 0.879950853 1.00000000
# Definimos una paleta de colores
colores <- colorRampPalette(c("blue", "white", "red"))(200)

# Visualizamos las correlaciones mediante un mapa de calor
corrplot(correlaciones, method = "color", col = colores, addCoef.col = "black")

# Visualizamos en un gráfico de dispersión la dependencia entre ingreso y premio
gplot = datos %>% 
  ggplot(mapping = aes(x=ingreso, y=premio, color=Genero)) +
  geom_point() +
  geom_smooth(formula= 'y ~ x', method = "lm", se = FALSE, color = "red") +
  theme_bw() + xlab("Ingreso") + ylab("Premio") + ggtitle("Relación entre ingreso y premio")

ggplotly(gplot)
# Visualizamos en un gráfico de dispersión la dependencia entre Edad e IMC
gplot = datos %>% 
  ggplot(mapping = aes(x=Edad, y=IMC, color=Genero)) +
  geom_point() +
  geom_smooth(formula= 'y ~ x', method = "lm", se = FALSE, color = "red") +
  theme_bw() + xlab("Edad") + ylab("IMC") + ggtitle("Relación entre Edad e IMC")

ggplotly(gplot)

En el gráfico se muestra claramente la correlación fuerte existente entre las variables ingreso y premio.

Además, las variables Edad e IMC presentan una correlación moderada.

Y las variables ingreso e IMC presentan una correlación débil.

El resto de las intersecciones no presentan correlaciones.



Parte 2: inferencia estadística

  1. Planteamos las hipótesis.
  2. Evaluamos la independencia de las muestras.
  3. Evaluamos normalidad. Se consideran las siguientes hipótesis >> H0: x es normal & H1: x no es normal
  4. Evaluamos homogeneidad de varianzas. Se consideran las siguientes hipótesis >> H0: Hay homogeneidad de varianzas & H1: No hay homogeneidad. Sirve para evitar cometer errores tipo I (falsos positivos) o tipo II (falsos negativos) y que esto afecte la validez de los resultados
  5. Seleccionamos el estadístico de prueba según 2), 3) y 4) y hacemos la comparación


a. Realizar pruebas de comparación de medias para la variable IMC según si fuma o no

  1. Planteamos las hipótesis
  • Ho -> No hay diferencias entre las medias del IMC de los grupos “Fuma = sí” y “Fuma = no”.

  • H1 -> Hay diferencias entre las medias de los dos grupos.

  • Tamaño de la muestra: 667

  • Nivel de Significancia: 0.05

  1. Evaluamos la independencia de las muestras. Considerando que:
  • Son dos grupos totalmente distintos (Fuma=Si y Fuma=No) y un caso del grupo A no puede existir en el grupo B.
  • La observación del Grupo A no puede inferir en la observación del Grupo B.
  • No hay ninguna relación aparente entre ambos grupos.

Se consideran dos muestras independientes.

  1. Evaluamos normalidad. Se consideran las siguientes hipótesis >> H0: x es normal & H1: x no es normal
# Verificamos mediante un QQPlot
gplot <- datos %>%
  ggplot(aes(sample = IMC, color = Fuma)) +
  geom_qq() + geom_qq_line() +
  facet_wrap(~ Fuma) + 
  ggtitle("QQ-plot de IMC por estado de fumador") +
  theme_bw()

ggplotly(gplot)

Aparentemente ambas muestras siguen una distribución normal.

Verificamos con una función estadística (usamos Lilliefors porque el tamaño de la muestra es mayor a 50)

by(data = datos, INDICES = datos$Fuma, FUN = function(x) { lillie.test(x$IMC) })
## datos$Fuma: no
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$IMC
## D = 0.030947, p-value = 0.2444
## 
## ------------------------------------------------------------------- 
## datos$Fuma: si
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$IMC
## D = 0.045829, p-value = 0.7123

p-value >= 0.05 en ambos grupos: NO hay evidencia estadística para rechazar H0, lo que indica que se puede suponer que los datos de la variable IMC siguen una distribución normal.

  1. Evaluamos homogeneidad de varianzas. Se consideran las siguientes hipótesis >> H0: Hay homogeneidad de varianzas & H1: No hay homogeneidad
bartlett.test(IMC ~ Fuma, data=datos)
## 
##  Bartlett test of homogeneity of variances
## 
## data:  IMC by Fuma
## Bartlett's K-squared = 0.35468, df = 1, p-value = 0.5515
leveneTest(IMC ~ Fuma, data=datos) # Se usa cuando no se puede asegurar la normalidad

En ambos tests se observa un p-value alejado del 0.05, por lo cual no hay evidencia para rechazar H0, lo que permite suponer que hay homogeneidad de varianzas.

  1. Seleccionamos el estadístico de prueba según 2), 3) y 4) y hacemos la comparación

Como las muestras se suponen con distribución normal y las varianzas homogéneas, se utilizará el t.test para hacer la prueba de hipótesis.

t.test(IMC ~ Fuma, alternative = "two.sided", mu = 0, var.equal = TRUE, data=datos) # p-value = 0.2055
## 
##  Two Sample t-test
## 
## data:  IMC by Fuma
## t = -1.2673, df = 665, p-value = 0.2055
## alternative hypothesis: true difference in means between group no and group si is not equal to 0
## 95 percent confidence interval:
##  -1.8990106  0.4092541
## sample estimates:
## mean in group no mean in group si 
##         30.32296         31.06784

Como se pueden considerar ambas muestras con distribución normal, independientes y con varianzas homogéneas, se realizó un test t de Student para comparar las medias de IMC de los grupos “No fumadores” y “Fumadores”.

Como el p-valor está alejado y mayor del 0,05 NO hay evidencia suficiente para rechazar H0, lo que presupone que no existe una diferencia significativa en la variación del promedio del IMC entre ambos grupos de la población.


b. Realizar pruebas de comparación de medias para la variable ingreso según género. Si considera que hay alguna hipótesis de interés a probar, según lo observado en la Parte 1, realizar el test correspondiente

  1. Planteamos las hipótesis
  • Ho -> No hay diferencias entre las medias del ingreso de los grupos “Genero = femenino” y “Genero = masculino”.

  • H1 -> Hay diferencias entre las medias de los dos grupos.

  • Tamaño de la muestra: 667

  • Nivel de Significancia: 0.05

  1. Evaluamos la independencia de las muestras. Considerando que:
  • Son dos grupos totalmente distintos (Genero = “femenino” y Genero = “masculino”) y un caso del grupo A no puede existir en el grupo B.
  • La observación del Grupo A no puede inferir en la observación del Grupo B.
  • No hay ninguna relación aparente entre ambos grupos.

Se consideran dos muestras independientes.

  1. Evaluamos normalidad. Se consideran las siguientes hipótesis >> H0: x es normal & H1: x no es normal
# Verificamos mediante un QQPlot
gplot <- datos %>%
  ggplot(aes(sample = ingreso, color = Genero)) +
  geom_qq() + geom_qq_line() +
  facet_wrap(~ Genero) + 
  ggtitle("QQ-plot de ingreso por Género") +
  theme_bw()

ggplotly(gplot)

Aparentemente ambas muestras siguen una distribución normal.

Verificamos con una función estadística (usamos Lilliefors porque el tamaño de la muestra es mayor a 50)

by(data = datos, INDICES = datos$Genero, FUN = function(x) { lillie.test(x$ingreso) })
## datos$Genero: femenino
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$ingreso
## D = 0.032072, p-value = 0.5839
## 
## ------------------------------------------------------------------- 
## datos$Genero: masculino
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$ingreso
## D = 0.029988, p-value = 0.6313

p-value >= 0.05 en ambos grupos: NO hay evidencia estadística para rechazar H0, lo que indica que se puede suponer que los datos de la variable ingreso siguen una distribución normal cuando la agrupamos por Genero

  1. Evaluamos homogeneidad de varianzas. Se consideran las siguientes hipótesis >> H0: Hay homogeneidad de varianzas & H1: No hay homogeneidad
bartlett.test(ingreso ~ Genero, data=datos)
## 
##  Bartlett test of homogeneity of variances
## 
## data:  ingreso by Genero
## Bartlett's K-squared = 6.4844, df = 1, p-value = 0.01088
leveneTest(ingreso ~ Genero, data=datos) # Se usa cuando no se puede asegurar la normalidad

En ambos tests se observa un p-value menor al 0.05, por lo cual se rechaza H0, que se interpreta que las varianzas no son homogéneas.

  1. Seleccionamos el estadístico de prueba según 2), 3) y 4) y hacemos la comparación

Como las muestras se suponen con distribución normal y las varianzas heterogénas, se utilizará el test de Welch para hacer la prueba de hipótesis.

oneway.test(ingreso ~ Genero, data=datos)
## 
##  One-way analysis of means (not assuming equal variances)
## 
## data:  ingreso and Genero
## F = 161.87, num df = 1.00, denom df = 662.21, p-value < 2.2e-16
t.test(ingreso ~ Genero, alternative = "two.sided", mu = 0, var.equal = FALSE, data=datos)
## 
##  Welch Two Sample t-test
## 
## data:  ingreso by Genero
## t = -12.723, df = 662.21, p-value < 2.2e-16
## alternative hypothesis: true difference in means between group femenino and group masculino is not equal to 0
## 95 percent confidence interval:
##  -245.7775 -180.0568
## sample estimates:
##  mean in group femenino mean in group masculino 
##                990.4566               1203.3738

En ambos test se obtuvo un p-valor muy pequeño lo que indica que se rechaza H0, por lo tanto se puede decir que, estadísticamente, la media poblacional de ingresos entre ambos géneros es diferente.


t.test(ingreso ~ Genero, alternative = "greater", mu = 0, var.equal = FALSE, data=datos)
## 
##  Welch Two Sample t-test
## 
## data:  ingreso by Genero
## t = -12.723, df = 662.21, p-value = 1
## alternative hypothesis: true difference in means between group femenino and group masculino is greater than 0
## 95 percent confidence interval:
##  -240.4826       Inf
## sample estimates:
##  mean in group femenino mean in group masculino 
##                990.4566               1203.3738

Conclusión: Se puede observar que el p-valor = 1 por lo que se NO se rechaza la Hipótesis Nula, confirmando estadísticamente que la media poblacional de ingresos del género masculino es mayor a la media de ingresos del genero femenino.


c. Realizar pruebas de comparación de medias para las variables IMC, ingreso y premio según Región

  1. Planteamos las hipótesis en forma general
  • Ho -> No hay diferencias entre las medias de IMC, ingreso y premio por Region.

  • H1 -> Hay alguna media diferente entre las regiones.

  • Tamaño de la muestra: 667

  • Nivel de Significancia: 0.05

  1. Evaluamos la independencia de las muestras. Considerando que:
  • Son cuatro grupos totalmente distintos y un caso de un grupo no puede existir en los otros.
  • La observación de un grupo no puede inferir en la observación de otros.
  • No hay ninguna relación aparente entre los grupos.

Se consideran cuatro muestras independientes.

Ahora vamos a analizar IMC por Región

  1. Evaluamos normalidad. Se consideran las siguientes hipótesis >> H0: x es normal & H1: x no es normal
# Verificamos mediante un QQPlot
gplot <- datos %>%
  ggplot(aes(sample = IMC, color = Region)) +
  geom_qq() + geom_qq_line() +
  facet_wrap(~ Region) + 
  ggtitle("QQ-plot de IMC por Región") +
  theme_bw()

ggplotly(gplot)

Aparentemente las muestras siguen una distribución normal.

Verificamos con una función estadística (usamos Lilliefors porque el tamaño de la muestra es mayor a 50)

by(data = datos, INDICES = datos$Region, FUN = function(x) { lillie.test(x$IMC) })
## datos$Region: nordeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$IMC
## D = 0.04531, p-value = 0.5743
## 
## ------------------------------------------------------------------- 
## datos$Region: noroeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$IMC
## D = 0.06141, p-value = 0.134
## 
## ------------------------------------------------------------------- 
## datos$Region: sureste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$IMC
## D = 0.040232, p-value = 0.7278
## 
## ------------------------------------------------------------------- 
## datos$Region: suroeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$IMC
## D = 0.040478, p-value = 0.7025

p-value >= 0.05 en los cuatro grupos: NO hay evidencia estadística para rechazar H0, lo que indica que se puede suponer que los datos de la variable IMC siguen una distribución normal cuando la agrupamos por Región

  1. Evaluamos homogeneidad de varianzas. Se consideran las siguientes hipótesis >> H0: Hay homogeneidad de varianzas & H1: No hay homogeneidad
bartlett.test(IMC ~ Region, data=datos)
## 
##  Bartlett test of homogeneity of variances
## 
## data:  IMC by Region
## Bartlett's K-squared = 9.978, df = 3, p-value = 0.01875
leveneTest(IMC ~ Region, data=datos) # Se usa cuando no se puede asegurar la normalidad

En ambos tests se observa un p-value menor al 0.05, por lo cual se rechaza H0, por lo que se interpreta que las varianzas no son homogéneas.

  1. Seleccionamos el estadístico de prueba según 2), 3) y 4) y hacemos la comparación

Como las muestras se suponen con distribución normal y las varianzas heterogénas, se utilizará el test de Welch para hacer la prueba de hipótesis.

oneway.test(IMC ~ Region, data=datos)
## 
##  One-way analysis of means (not assuming equal variances)
## 
## data:  IMC and Region
## F = 19.231, num df = 3.00, denom df = 367.54, p-value = 1.325e-11
kruskal.test(IMC ~ Region, data = datos)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  IMC by Region
## Kruskal-Wallis chi-squared = 51.743, df = 3, p-value = 3.397e-11

En ambos tests se obtuvo un p-valor muy pequeño lo que indica que se rechaza H0, por lo tanto se puede decir que, estadísticamente, la media poblacional de IMC entre las regiones es diferente.

Se va a utilizar una función para evaluar de a pares de regiones las medias de IMC, a fin de identificar cuales son las medias que difieren.


comparar_dos_regiones = function(ds, nombre_variable){
  regiones_unicas = ds %>% distinct(Region)
  lst = as.list(as.data.frame(t(regiones_unicas)))
  
  pvalores_ds = data.frame(variables = character(), p_valor=character())
  
  formula_str <- reformulate("Region", nombre_variable)
  
  while(length(lst)>1){
    region_A = as.character(lst[1])
    
    lst = lst[-1]
    
    for(region_B in lst){
      region_B = as.character(region_B)
      
      working_ds = ds %>% filter(Region %in% c(region_A, region_B))
      
      rdo = t.test(formula_str, alternative = "two.sided", mu = 0, var.equal = FALSE, data=working_ds)
      
      label = paste0(region_A,"-",region_B)
pvalores_ds = pvalores_ds %>% union(data.frame(variables=label, p_valor=as.character(rdo[["p.value"]])))
    }
  }

  return(pvalores_ds)
}

dt = comparar_dos_regiones(datos, "IMC")
kable(dt, caption="<center><b>Resultado Test t de Student (p-valor) - IMC cada 2 Regiones</b></center>")
Table:
Resultado Test t de Student (p-valor) - IMC cada 2 Regiones
variables p_valor
nordeste-sureste 2.29543858727147e-11
nordeste-noroeste 0.537331304440342
nordeste-suroeste 0.00171066577169515
sureste-noroeste 4.13625651114826e-10
sureste-suroeste 7.79698255660573e-05
noroeste-suroeste 0.00993143266327661

De acuerdo al test t de Student, todos tienen los p-valores muy cercanos a 0, por lo que se rechaza H0 en todos los casos excepto para el par de regiones “nordeste-noroeste”.

Analizando el par “nordeste-noroeste” se puede observar que el p-valor es 0.5373, muy alto, por lo que no hay evidencia para rechazar H0 y se podria contemplar que estadísticamente la media de IMC de ambas poblaciones son iguales.


Ahora vamos a analizar ingreso por Región

  1. Evaluamos normalidad. Se consideran las siguientes hipótesis >> H0: x es normal & H1: x no es normal
# Verificamos mediante un QQPlot
gplot <- datos %>%
  ggplot(aes(sample = ingreso, color = Region)) +
  geom_qq() + geom_qq_line() +
  facet_wrap(~ Region) + 
  ggtitle("QQ-plot de ingreso por Región") +
  theme_bw()

ggplotly(gplot)

Aparentemente las muestras siguen una distribución normal.

Verificamos con una función estadística (usamos Lilliefors porque el tamaño de la muestra es mayor a 50)

by(data = datos, INDICES = datos$Region, FUN = function(x) { lillie.test(x$ingreso) })
## datos$Region: nordeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$ingreso
## D = 0.048198, p-value = 0.4735
## 
## ------------------------------------------------------------------- 
## datos$Region: noroeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$ingreso
## D = 0.043916, p-value = 0.6098
## 
## ------------------------------------------------------------------- 
## datos$Region: sureste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$ingreso
## D = 0.058215, p-value = 0.1775
## 
## ------------------------------------------------------------------- 
## datos$Region: suroeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$ingreso
## D = 0.043712, p-value = 0.5843

p-value >= 0.05 en los cuatro grupos: NO hay evidencia estadística para rechazar H0, lo que indica que se puede suponer que los datos de la variable ingreso siguen una distribución normal cuando la agrupamos por Región

  1. Evaluamos homogeneidad de varianzas. Se consideran las siguientes hipótesis >> H0: Hay homogeneidad de varianzas & H1: No hay homogeneidad
bartlett.test(ingreso ~ Region, data=datos)
## 
##  Bartlett test of homogeneity of variances
## 
## data:  ingreso by Region
## Bartlett's K-squared = 8.4901, df = 3, p-value = 0.0369
leveneTest(ingreso ~ Region, data=datos) # Se usa cuando no se puede asegurar la normalidad

En ambos tests se observa un p-value menor al 0.05, por lo cual se rechaza H0, por lo que se interpreta que las varianzas no son homogéneas.

  1. Seleccionamos el estadístico de prueba según 2), 3) y 4) y hacemos la comparación

Como las muestras se suponen con distribución normal y las varianzas heterogénas, se utilizará el test de Welch para hacer la prueba de hipótesis.

oneway.test(ingreso ~ Region, data=datos)
## 
##  One-way analysis of means (not assuming equal variances)
## 
## data:  ingreso and Region
## F = 1.164, num df = 3.00, denom df = 367.84, p-value = 0.3233
kruskal.test(ingreso ~ Region, data = datos)
## 
##  Kruskal-Wallis rank sum test
## 
## data:  ingreso by Region
## Kruskal-Wallis chi-squared = 2.9365, df = 3, p-value = 0.4015

En ambos tests se obtuvo un p-valor > 0.05 lo que indica que NO hay evidencia para rechazar H0, por lo tanto se puede decir que, estadísticamente, la media poblacional de ingreso entre las regiones es similar.

Se va a utilizar una función para evaluar de a pares de regiones las medias de ingreso, a fin de corroborar la conclusión anterior.


dt = comparar_dos_regiones(datos, "ingreso")
kable(dt, caption="<center><b>Resultado Test t de Student (p-valor) - ingreso cada 2 Regiones</b></center>")
Table:
Resultado Test t de Student (p-valor) - ingreso cada 2 Regiones
variables p_valor
nordeste-sureste 0.228525487375051
nordeste-noroeste 0.608749809791648
nordeste-suroeste 0.526807312402343
sureste-noroeste 0.0792080745348705
sureste-suroeste 0.604634481804345
noroeste-suroeste 0.255010367991364


Ahora vamos a analizar premio por Región

  1. Evaluamos normalidad. Se consideran las siguientes hipótesis >> H0: x es normal & H1: x no es normal
# Verificamos mediante un QQPlot
gplot <- datos %>%
  ggplot(aes(sample = premio, color = Region)) +
  geom_qq() + geom_qq_line() +
  facet_wrap(~ Region) + 
  ggtitle("QQ-plot de Premio por Región") +
  theme_bw()

ggplotly(gplot)

Aparentemente las muestras siguen una distribución normal.

Verificamos con una función estadística (usamos Lilliefors porque el tamaño de la muestra es mayor a 50)

by(data = datos, INDICES = datos$Region, FUN = function(x) { lillie.test(x$premio) })
## datos$Region: nordeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$premio
## D = 0.045881, p-value = 0.554
## 
## ------------------------------------------------------------------- 
## datos$Region: noroeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$premio
## D = 0.046633, p-value = 0.5126
## 
## ------------------------------------------------------------------- 
## datos$Region: sureste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$premio
## D = 0.052678, p-value = 0.3056
## 
## ------------------------------------------------------------------- 
## datos$Region: suroeste
## 
##  Lilliefors (Kolmogorov-Smirnov) normality test
## 
## data:  x$premio
## D = 0.029289, p-value = 0.9742

p-value >= 0.05 en los cuatro grupos: NO hay evidencia estadística para rechazar H0, lo que indica que se puede suponer que los datos de la variable premio siguen una distribución normal cuando la agrupamos por Región

  1. Evaluamos homogeneidad de varianzas. Se consideran las siguientes hipótesis >> H0: Hay homogeneidad de varianzas & H1: No hay homogeneidad
bartlett.test(premio ~ Region, data=datos)
## 
##  Bartlett test of homogeneity of variances
## 
## data:  premio by Region
## Bartlett's K-squared = 3.4976, df = 3, p-value = 0.3211
leveneTest(premio ~ Region, data=datos) # Se usa cuando no se puede asegurar la normalidad

En ambos tests se observa un p-value mayor a 0.05, por lo cual NO hay evidencia para rechazar H0, por lo que se interpreta que las varianzas son homogéneas.

  1. Seleccionamos el estadístico de prueba según 2), 3) y 4) y hacemos la comparación

Como las muestras se suponen con distribución normal, las varianzas son homogéneas y se trata de varios grupos, se utilizará el test ANOVA para hacer la prueba de hipótesis.

anova_result <- aov(premio ~ Region, data = datos)
summary(anova_result)
##              Df Sum Sq Mean Sq F value Pr(>F)
## Region        3    2.4   0.801   0.187  0.905
## Residuals   663 2833.3   4.273
oneway.test(premio ~ Region, data=datos, var.equal = TRUE) # p-value = 0.905
## 
##  One-way analysis of means
## 
## data:  premio and Region
## F = 0.18744, num df = 3, denom df = 663, p-value = 0.905

En ambos tests se obtuvo un p-valor muy alto lo que indica que hay una fuerte evidencia para NO rechazar H0, por lo tanto se puede decir que, estadísticamente, la media poblacional de premio entre las regiones es similar.

Se va a utilizar una función para evaluar de a pares de regiones las medias de premio, a fin de corroborar la conclusión anterior.


dt = comparar_dos_regiones(datos, "premio")
kable(dt, caption="<center><b>Resultado Test t de Student (p-valor) - Premio cada 2 Regiones</b></center>")
Table:
Resultado Test t de Student (p-valor) - Premio cada 2 Regiones
variables p_valor
nordeste-sureste 0.688064368252902
nordeste-noroeste 0.732396906064601
nordeste-suroeste 0.925471665312624
sureste-noroeste 0.445882813507527
sureste-suroeste 0.627025171971952
noroeste-suroeste 0.813280564328186


Procedemos a ejecutar dos tests Post-HOC: test de Tukey y Bonferroni

intervalos = TukeyHSD(anova_result) 
plot(intervalos) 

pairwise.t.test(x = datos$premio, g = datos$Region, p.adjust.method = "bonferroni",
                pool.sd = TRUE, paired = FALSE, alternative = "two.sided")
## 
##  Pairwise comparisons using t tests with pooled SD 
## 
## data:  datos$premio and datos$Region 
## 
##          nordeste noroeste sureste
## noroeste 1        -        -      
## sureste  1        1        -      
## suroeste 1        1        1      
## 
## P value adjustment method: bonferroni

Con ambos tests corroboramos la conclusión del ANOVA


d. Probar si puede asumirse independencia entre la procedencia (Región) y la condición de fumador de la persona

Para evaluar dependencia vamos a realizar Tablas de Contingencia, que nos permiten evaluar dos variables cualitativas y buscar una relación entre ellas.

Comparamos la tabla de frecuencias observadas con la tabla de frecuencias esperada (suponiendo independencia) utilizando un estadístico de prueba.

  1. Plantear las hipótesis:

Siendo >> X = Región & Y = Fuma

  • H0: X e Y son independientes.
  • H1: Hay alguna dependencia entre ellas.
  1. Armarmos la tabla de frecuencias
frecuencias = table(datos$Region, datos$Fuma)

margin.table(frecuencias, 1)  
## 
## nordeste noroeste  sureste suroeste 
##      162      165      168      172
margin.table(frecuencias, 2)
## 
##  no  si 
## 535 132
prop.table(frecuencias)
##           
##                    no         si
##   nordeste 0.19640180 0.04647676
##   noroeste 0.19790105 0.04947526
##   sureste  0.19040480 0.06146927
##   suroeste 0.21739130 0.04047976
  1. Ejecutamos la prueba de independencia, utilizando el test chi cuadrado
chisq.test(frecuencias, correct = F)
## 
##  Pearson's Chi-squared test
## 
## data:  frecuencias
## X-squared = 4.1168, df = 3, p-value = 0.2491

Conclusión: En el test de Chi cuadrado sobre la tabla de frencuencias se observa un p-valor 0.2491, es bastante mayor a 0.05, no hay evidencia para rechazar H0.

Esto indicaría que estadísticamente se puede considerar que hay independencia entre ambas variables cualitativas: Region - Fuma

Entonces, NO hay evidencia suficiente para afirmar que la condición de fumador dependa de la región.

  1. Corroborar niveles de asociación mediante el Coeficiente de Contingencia y V de Cramer
assocstats(frecuencias)
##                     X^2 df P(> X^2)
## Likelihood Ratio 4.1061  3  0.25023
## Pearson          4.1168  3  0.24913
## 
## Phi-Coefficient   : NA 
## Contingency Coeff.: 0.078 
## Cramer's V        : 0.079

Corroborando los niveles de asociación se obtienen indices muy bajos lo que refuerza la evidencia de independencia obtenida por el test de Chi cuadrado.

FIN


LS0tCnRpdGxlOiAiVHJhYmFqbyBQcsOhY3RpY28gRmluYWwiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OgogICAgICBjb2xsYXBzZWQ6IGZhbHNlCiAgICAgIHNtb290aF9zY3JvbGw6IHRydWUKICAgIGNvZGVfZm9sZGluZzogc2hvdwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICB0aGVtZTogdW5pdGVkCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmVkaXRvcl9vcHRpb25zOiAKICBtYXJrZG93bjogCiAgICB3cmFwOiA3MgotLS0KCmBgYHtjc3MgZWNobz1GQUxTRX0KLmJhZENvZGUgewpiYWNrZ3JvdW5kLWNvbG9yOiB3aGl0ZTsKfQpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsIAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLCAKICAgICAgICAgICAgICAgICAgICAgIGV2YWwgPSBUUlVFLCAKICAgICAgICAgICAgICAgICAgICAgIGZpZy53aWR0aCA9IDYsIAogICAgICAgICAgICAgICAgICAgICAgZmlnLmhlaWdodCA9IDQsIAogICAgICAgICAgICAgICAgICAgICAgZmlnLmFsaWduID0gImNlbnRlciIsIAogICAgICAgICAgICAgICAgICAgICAgY2xhc3Muc291cmNlID0gImJhZENvZGUiKSAKb3B0aW9ucyh3aWR0aCA9IDkwKQpgYGAKCjxicj4gPGJyPgoKfCAgfCAgfAp8LS0tLS0tLS0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCAqKlVuaXZlcnNpZGFkKiogfCBVbml2ZXJzaWRhZCBOYWNpb25hbCBkZWwgT2VzdGUgfAp8ICoqQ2FycmVyYSoqICAgICB8IEVzcC4gZW4gQ2llbmNpYSBkZSBEYXRvcyB8CnwgKipNYXRlcmlhKiogICAgIHwgRnVuZGFtZW50b3MgZGUgRXN0YWTDrXN0aWNhcyAoMDEwNTApIHwKfCAqKlByb2Zlc29yYSoqICAgfCBNZy4gU2MuIFNpbHZpYSBOLiBQw6lyZXogfAp8ICoqR3J1cG8qKiAgICAgICB8IE7CuiAzIHwgICAgICAgIAp8ICoqQWx1bW5vcyoqICAgICB8IHtMaWMuIExldGljaWEgU29zYSwgSW5nLiBGZWRlcmljbyBDemVybmlhd3NraSwgTWcuIFBhYmxvIFBhbmRvbGZvfSB8CnwgKipGZWNoYSoqICAgICAgIHwgSnVuaW8gMjAyNSB8CnwgIHwgIHwKCjxicj4gPGJyPgoKIyMgTGlicmVyaWFzIHVzYWRhcwoKYGBge3J9CmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkoaHJicnRoZW1lcykKbGlicmFyeShwbG90bHkpCmxpYnJhcnkodGlkeXIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShjYXIpCmxpYnJhcnkobm9ydGVzdCkKbGlicmFyeSh0c2VyaWVzKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KHZjZCkKYGBgCgo8YnI+IDxicj4KCiMjIEltcG9ydGFjacOzbiBkZSBsYSBiYXNlIGRlIGRhdG9zCgpgYGB7cn0KIyBCb3JyYW1vcyBhbWJpZW50ZSBkZSB0cmFiYWpvCnJtKGxpc3QgPSBscygpKQojIFNldGVhbW9zIGRpcmVjdG9yaW8gZGUgdHJhYmFqbwpzZXR3ZCgiL1VzZXJzL3BwYW5kby9NYXRlcmlhcy9kYXRhL21hdGVyaWFzL2VzdGFkaXN0aWNhL3RwX2dydXBhbCIpCiMgQ2FyZ2Ftb3MgZGF0b3MgZGVsIGFyY2hpdm8KZGF0b3MgPC0gcmVhZF94bHN4KCJzZWd1cm9zLnhsc3giKQojIE1vc3RyYW1vcyBsb3MgcHJpbWVyb3MgNiBjYXNvcwpoZWFkKGRhdG9zKQpgYGAKCjxicj4gPGJyPgoKIyMgUGFydGUgMTogYW7DoWxpc2lzIGV4cGxvcmF0b3JpbwoKPGJyPgoKIyMjIGEuIElkZW50aWZpY2FyIGVsIHRpcG8gZGUgY2FkYSB1bmEgZGUgbGFzIHZhcmlhYmxlcyByZWdpc3RyYWRhcyAoY3VhbGksIGN1YW50aSkKCmBgYHtyfQojIE1vc3RyYW1vcyBlc3RydWN0dXJhIGRlIGxvcyBkYXRvcwpzdHIoZGF0b3MpCmBgYAo8YnI+Cgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9Ci0gY3VhbGl0YXRpdmFzIG5vbWluYWxlcyA9IHtHZW5lcm8sIEZ1bWEsIFJlZ2lvbn0KLSBjdWFudGl0YXRpdmFzOiAKICAtIGRpc2NyZXRhcyA9IHtFZGFkfQogIC0gY29udGludWFzID0ge0lNQywgaW5ncmVzbywgcHJlbWlvfQo6OjoKCjxicj4KCiMjIyBiLiBEZWNpZGlyIHNpIGhheSBkYXRvcyBmYWx0YW50ZXMsIGVuIGN1eW8gY2FzbyBlbGltaW5hciBsb3MgY2Fzb3MKCmBgYHtyfQojIENvbnRhbW9zIG7Dum1lcm8gZGUgbnVsb3MgcG9yIHZhcmlhYmxlcyAoY29sdW1uYXMpCnNhcHBseShkYXRvcywgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkKCiMgRWxpbWluYW1vcyBjYXNvcyAoZmlsYXMpIGNvbiBudWxvcwpkYXRvcyA8LSBkYXRvc1shaXMubmEoZGF0b3MkRnVtYSksXQoKIyBWZXJpZmljYW1vcyBxdWUgZWwgY2FzbyBjb24gbnVsb3MgZnVlIGVsaW1pbmFkbwpzYXBwbHkoZGF0b3MsIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpCmBgYAoKPGJyPgoKIyMjIGMuIFJlYWxpemFyIGJveHBsb3RzIHBhcmEgY2FkYSB2YXJpYWJsZSBjdWFudGl0YXRpdmEsIHNlcGFyYW5kbyBzZWfDum4gbGEvbGFzIHZhcmlhYmxlcyBjdWFsaXRhdGl2YXMgcXVlIGNvbnNpZGVyZSBpbXBvcnRhbnRlcwoKYGBge3J9CnNlZ3Vyb3NfbG9uZ19HZW5lcm8gPC0gZGF0b3MgJT4lCiAgc2VsZWN0KEVkYWQsIEdlbmVybywgSU1DLCBpbmdyZXNvLCBwcmVtaW8pICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLUdlbmVybywgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsb3IiKQoKZ2dwbG90bHkoCiAgZ2dwbG90KHNlZ3Vyb3NfbG9uZ19HZW5lcm8sIGFlcyh4ID0gR2VuZXJvLCB5ID0gdmFsb3IsIGZpbGwgPSBHZW5lcm8pKSArCiAgICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcpICsKICAgIGZhY2V0X3dyYXAofiB2YXJpYWJsZSwgc2NhbGVzID0gImZyZWVfeSIpICsgICMgVW4gcGFuZWwgcG9yIHZhcmlhYmxlCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSB2YXJpYWJsZXMgcG9yIEdlbmVybyIsCiAgICAgIHggPSAiR8OpbmVybyIsCiAgICAgIHkgPSAiVmFsb3IiCiAgICApCikKCnNlZ3Vyb3NfbG9uZ19GdW1hIDwtIGRhdG9zICU+JQogIHNlbGVjdChFZGFkLCBJTUMsIEZ1bWEsIGluZ3Jlc28sIHByZW1pbykgJT4lCiAgcGl2b3RfbG9uZ2VyKGNvbHMgPSAtRnVtYSwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsb3IiKQoKZ2dwbG90bHkoCiAgZ2dwbG90KHNlZ3Vyb3NfbG9uZ19GdW1hLCBhZXMoeCA9IEZ1bWEsIHkgPSB2YWxvciwgZmlsbCA9IEZ1bWEpKSArCiAgICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcpICsKICAgIGZhY2V0X3dyYXAofiB2YXJpYWJsZSwgc2NhbGVzID0gImZyZWVfeSIpICsgICMgVW4gcGFuZWwgcG9yIHZhcmlhYmxlCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSB2YXJpYWJsZXMgcG9yIENvbmRpY2nDs24gZGUgRnVtYWRvciIsCiAgICAgIHggPSAiRnVtYSIsCiAgICAgIHkgPSAiVmFsb3IiCiAgICApCikKCnNlZ3Vyb3NfbG9uZ19SZWdpb24gPC0gZGF0b3MgJT4lCiAgc2VsZWN0KEVkYWQsIElNQywgUmVnaW9uLCBpbmdyZXNvLCBwcmVtaW8pICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLVJlZ2lvbiwgbmFtZXNfdG8gPSAidmFyaWFibGUiLCB2YWx1ZXNfdG8gPSAidmFsb3IiKQoKZ2dwbG90bHkoCiAgZ2dwbG90KHNlZ3Vyb3NfbG9uZ19SZWdpb24sIGFlcyh4ID0gUmVnaW9uLCB5ID0gdmFsb3IsIGZpbGwgPSBSZWdpb24pKSArCiAgICBnZW9tX2JveHBsb3QoYWxwaGEgPSAwLjcpICsKICAgIGZhY2V0X3dyYXAofiB2YXJpYWJsZSwgc2NhbGVzID0gImZyZWVfeSIpICsgICMgVW4gcGFuZWwgcG9yIHZhcmlhYmxlCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgbGFicygKICAgICAgdGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSB2YXJpYWJsZXMgcG9yIFJlZ2lvbiIsCiAgICAgIHggPSAiUmVnacOzbiIsCiAgICAgIHkgPSAiVmFsb3IiCiAgICApCikKCmBgYAoKOjo6IHtzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5OyBjb2xvcjogYmxhY2sifQpTZSBvYnNlcnZhIHF1ZSBsYXMgdmFyaWFibGVzIGN1YW50aXRhdGl2YXMgYWdydXBhZGFzIHBvciBsYXMgZGlzdGludGFzIGN1YWxpdGF0aXZhcyBwcmVzZW50YW4gZGlzdHJpYnVjaW9uZXMgc2ltaWxhcmVzLgoKQWRlbcOhcywgbGEgdmFyaWFibGUgcHJlbWlvIHByZXNlbnRhIHVuIHZhbG9yIG11eSBhdMOtcGljby4KOjo6Cgo8YnI+CgojIyMgZC4gSWRlbnRpZmljYXIgc2kgaGF5IGRhdG9zIG11eSBhdMOtcGljb3MsIGVuIGN1eW8gY2FzbyBlbGltaW5hciBsb3MgY2Fzb3MKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KQ29tbyBzZSBjb25jbHV5ZSBkZWwgYW7DoWxpc2lzIGFudGVyaW9yLCBsYSB2YXJpYWJsZSBwcmVtaW8gcHJlc2VudGEgdW4gdmFsb3IgbXV5IGF0w61waWNvLgoKUHJvY2VkZW1vcyBhIGVsaW1pbmFybG8uCjo6OgoKCmBgYHtyfQpncGxvdCA9IGRhdG9zICU+JSBmaWx0ZXIoR2VuZXJvID09ICJmZW1lbmlubyIpICU+JSAKICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4PVJlZ2lvbiwgeT1wcmVtaW8sIGNvbG9yPUZ1bWEpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzdGF0X3N1bW1hcnkoZnVuID0ibWVhbiIsIGdlb209ImNyb3NzYmFyIiwgY29sb3I9InJlZCIsIGxpbmV3aWR0aD0wLjUpICsgIyBtb3N0cmFtb3MgbGEgbWVkaWEKICB0aGVtZV9idygpICsgeGxhYigiUmVnaW9uIikgKyB5bGFiKCJQcmVtaW8iKQoKZ2dwbG90bHkoZ3Bsb3QpCgojIExvIGVsaW1pbmFtb3MKZGF0b3MgPC0gZGF0b3MgJT4lIGZpbHRlcihwcmVtaW8gIT0gbWF4KHByZW1pbykpCmBgYAoKPGJyPgoKIyMjIGUuIEhhbGxhciBsYXMgbWVkaWRhcyByZXN1bWVuIGRlIGNhZGEgdmFyaWFibGUgY3VhbnRpdGF0aXZhLCBzZXBhcmFuZG8gc2Vnw7puIGxvIGhlY2hvIGVuIGVsIMOtdGVtIGFudGVyaW9yCgpgYGB7cn0KIyBEZWNsYXJhbW9zIGEgbGFzIHZhcmlhYmxlcyBjdWFsaXRhdGl2YXMgY29tbyBmYWN0b3IsIHBhcmEgcG9kZXIgcmVjb25vY2VyIGNhdGVnb3JpYXMKZGF0b3MkR2VuZXJvIDwtIGFzLmZhY3RvcihkYXRvcyRHZW5lcm8pCmRhdG9zJEZ1bWEgPC0gYXMuZmFjdG9yKGRhdG9zJEZ1bWEpCmRhdG9zJFJlZ2lvbiA8LSBhcy5mYWN0b3IoZGF0b3MkUmVnaW9uKQoKIyBNb3N0cmFtb3MgbWVkaWRhcyByZXN1bWVuCnN1bW1hcnkoZGF0b3MpCgojIFZvbHZlbW9zIGEgbW9zdHJhciBncmFmaWNhbWVudGUgbGFzIG1lZGlkYXMgcmVzdW1lbiBkZSBsYXMgdmFyaWFibGVzIGN1YW50aXMgYWdydXBhZGFzIHBvciBsYXMgdmFyaWFibGVzIGN1YWxpcwpzZWd1cm9zX2xvbmdfR2VuZXJvIDwtIGRhdG9zICU+JQogIHNlbGVjdChFZGFkLCBHZW5lcm8sIElNQywgaW5ncmVzbywgcHJlbWlvKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1HZW5lcm8sIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbG9yIikKCmdncGxvdGx5KAogIGdncGxvdChzZWd1cm9zX2xvbmdfR2VuZXJvLCBhZXMoeCA9IEdlbmVybywgeSA9IHZhbG9yLCBmaWxsID0gR2VuZXJvKSkgKwogICAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43KSArCiAgICBmYWNldF93cmFwKH4gdmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArICAjIFVuIHBhbmVsIHBvciB2YXJpYWJsZQogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgdmFyaWFibGVzIHBvciBHZW5lcm8iLAogICAgICB4ID0gIkfDqW5lcm8iLAogICAgICB5ID0gIlZhbG9yIgogICAgKQopCgpzZWd1cm9zX2xvbmdfRnVtYSA8LSBkYXRvcyAlPiUKICBzZWxlY3QoRWRhZCwgSU1DLCBGdW1hLCBpbmdyZXNvLCBwcmVtaW8pICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gLUZ1bWEsIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbG9yIikKCmdncGxvdGx5KAogIGdncGxvdChzZWd1cm9zX2xvbmdfRnVtYSwgYWVzKHggPSBGdW1hLCB5ID0gdmFsb3IsIGZpbGwgPSBGdW1hKSkgKwogICAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43KSArCiAgICBmYWNldF93cmFwKH4gdmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArICAjIFVuIHBhbmVsIHBvciB2YXJpYWJsZQogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgdmFyaWFibGVzIHBvciBDb25kaWNpw7NuIGRlIEZ1bWFkb3IiLAogICAgICB4ID0gIkZ1bWEiLAogICAgICB5ID0gIlZhbG9yIgogICAgKQopCgpzZWd1cm9zX2xvbmdfUmVnaW9uIDwtIGRhdG9zICU+JQogIHNlbGVjdChFZGFkLCBJTUMsIFJlZ2lvbiwgaW5ncmVzbywgcHJlbWlvKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IC1SZWdpb24sIG5hbWVzX3RvID0gInZhcmlhYmxlIiwgdmFsdWVzX3RvID0gInZhbG9yIikKCmdncGxvdGx5KAogIGdncGxvdChzZWd1cm9zX2xvbmdfUmVnaW9uLCBhZXMoeCA9IFJlZ2lvbiwgeSA9IHZhbG9yLCBmaWxsID0gUmVnaW9uKSkgKwogICAgZ2VvbV9ib3hwbG90KGFscGhhID0gMC43KSArCiAgICBmYWNldF93cmFwKH4gdmFyaWFibGUsIHNjYWxlcyA9ICJmcmVlX3kiKSArICAjIFVuIHBhbmVsIHBvciB2YXJpYWJsZQogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgIGxhYnMoCiAgICAgIHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgdmFyaWFibGVzIHBvciBSZWdpb24iLAogICAgICB4ID0gIlJlZ2nDs24iLAogICAgICB5ID0gIlZhbG9yIgogICAgKQopCgoKCmBgYAoKPGJyPgoKIyMjIGYuIENhbGN1bGFyIGxhIGNvcnJlbGFjacOzbiBlbnRyZSB0b2RvcyBsb3MgcGFyZXMgcG9zaWJsZXMgZGUgdmFyaWFibGVzIG51bcOpcmljYXMKCmBgYHtyfQojIENhbGN1bGFtb3MgbGEgbWF0cml6IGRlIGNvcnJlbGFjacOzbiBxdWUgbm9zIG11ZXN0cmEgbG9zIGNvZWZpY2llbnRlcyBkZSBjb3JyZWxhY2nDs24gZW50cmUgY2FkYSBwYXJhIGRlIHZhcmlhYmxlcy4gCmRhdG9zX251bWVyaWNvcyA8LSBkYXRvcyAlPiUgc2VsZWN0KEVkYWQsIElNQywgaW5ncmVzbywgcHJlbWlvKQpjb3JyZWxhY2lvbmVzIDwtIGNvcihkYXRvc19udW1lcmljb3MpCmNvcnJlbGFjaW9uZXMKCiMgRGVmaW5pbW9zIHVuYSBwYWxldGEgZGUgY29sb3Jlcwpjb2xvcmVzIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiYmx1ZSIsICJ3aGl0ZSIsICJyZWQiKSkoMjAwKQoKIyBWaXN1YWxpemFtb3MgbGFzIGNvcnJlbGFjaW9uZXMgbWVkaWFudGUgdW4gbWFwYSBkZSBjYWxvcgpjb3JycGxvdChjb3JyZWxhY2lvbmVzLCBtZXRob2QgPSAiY29sb3IiLCBjb2wgPSBjb2xvcmVzLCBhZGRDb2VmLmNvbCA9ICJibGFjayIpCgojIFZpc3VhbGl6YW1vcyBlbiB1biBncsOhZmljbyBkZSBkaXNwZXJzacOzbiBsYSBkZXBlbmRlbmNpYSBlbnRyZSBpbmdyZXNvIHkgcHJlbWlvCmdwbG90ID0gZGF0b3MgJT4lIAogIGdncGxvdChtYXBwaW5nID0gYWVzKHg9aW5ncmVzbywgeT1wcmVtaW8sIGNvbG9yPUdlbmVybykpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKGZvcm11bGE9ICd5IH4geCcsIG1ldGhvZCA9ICJsbSIsIHNlID0gRkFMU0UsIGNvbG9yID0gInJlZCIpICsKICB0aGVtZV9idygpICsgeGxhYigiSW5ncmVzbyIpICsgeWxhYigiUHJlbWlvIikgKyBnZ3RpdGxlKCJSZWxhY2nDs24gZW50cmUgaW5ncmVzbyB5IHByZW1pbyIpCgpnZ3Bsb3RseShncGxvdCkKCiMgVmlzdWFsaXphbW9zIGVuIHVuIGdyw6FmaWNvIGRlIGRpc3BlcnNpw7NuIGxhIGRlcGVuZGVuY2lhIGVudHJlIEVkYWQgZSBJTUMKZ3Bsb3QgPSBkYXRvcyAlPiUgCiAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeD1FZGFkLCB5PUlNQywgY29sb3I9R2VuZXJvKSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgoZm9ybXVsYT0gJ3kgfiB4JywgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSwgY29sb3IgPSAicmVkIikgKwogIHRoZW1lX2J3KCkgKyB4bGFiKCJFZGFkIikgKyB5bGFiKCJJTUMiKSArIGdndGl0bGUoIlJlbGFjacOzbiBlbnRyZSBFZGFkIGUgSU1DIikKCmdncGxvdGx5KGdwbG90KQoKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkVuIGVsIGdyw6FmaWNvIHNlIG11ZXN0cmEgY2xhcmFtZW50ZSBsYSBjb3JyZWxhY2nDs24gZnVlcnRlIGV4aXN0ZW50ZSBlbnRyZSBsYXMgdmFyaWFibGVzIGluZ3Jlc28geSBwcmVtaW8uCgpBZGVtw6FzLCBsYXMgdmFyaWFibGVzIEVkYWQgZSBJTUMgcHJlc2VudGFuIHVuYSBjb3JyZWxhY2nDs24gbW9kZXJhZGEuCgpZIGxhcyB2YXJpYWJsZXMgaW5ncmVzbyBlIElNQyBwcmVzZW50YW4gdW5hIGNvcnJlbGFjacOzbiBkw6liaWwuCgpFbCByZXN0byBkZSBsYXMgaW50ZXJzZWNjaW9uZXMgbm8gcHJlc2VudGFuIGNvcnJlbGFjaW9uZXMuCjo6OgoKPGJyPiA8YnI+CgojIyBQYXJ0ZSAyOiBpbmZlcmVuY2lhIGVzdGFkw61zdGljYQoKOjo6IHtzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5OyBjb2xvcjogYmxhY2sifQoxKSBQbGFudGVhbW9zIGxhcyBoaXDDs3Rlc2lzLgoyKSBFdmFsdWFtb3MgbGEgaW5kZXBlbmRlbmNpYSBkZSBsYXMgbXVlc3RyYXMuCjMpIEV2YWx1YW1vcyBub3JtYWxpZGFkLiBTZSBjb25zaWRlcmFuIGxhcyBzaWd1aWVudGVzIGhpcMOzdGVzaXMgPj4gSDA6IHggZXMgbm9ybWFsICYgSDE6IHggbm8gZXMgbm9ybWFsCjQpIEV2YWx1YW1vcyBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzLiBTZSBjb25zaWRlcmFuIGxhcyBzaWd1aWVudGVzIGhpcMOzdGVzaXMgPj4gSDA6IEhheSBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzICYgSDE6IE5vIGhheSBob21vZ2VuZWlkYWQuIFNpcnZlIHBhcmEgZXZpdGFyIGNvbWV0ZXIgZXJyb3JlcyB0aXBvIEkgKGZhbHNvcyBwb3NpdGl2b3MpIG8gdGlwbyBJSSAoZmFsc29zIG5lZ2F0aXZvcykgeSBxdWUgZXN0byBhZmVjdGUgbGEgdmFsaWRleiBkZSBsb3MgcmVzdWx0YWRvcyAKNSkgU2VsZWNjaW9uYW1vcyBlbCBlc3RhZMOtc3RpY28gZGUgcHJ1ZWJhIHNlZ8O6biAyKSwgMykgeSA0KSB5IGhhY2Vtb3MgbGEgY29tcGFyYWNpw7NuCjo6OgoKPGJyPgoKIyMjIGEuIFJlYWxpemFyIHBydWViYXMgZGUgY29tcGFyYWNpw7NuIGRlIG1lZGlhcyBwYXJhIGxhIHZhcmlhYmxlIElNQyBzZWfDum4gc2kgZnVtYSBvIG5vCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CjEpIFBsYW50ZWFtb3MgbGFzIGhpcMOzdGVzaXMKLSBIbyAtPiBObyBoYXkgZGlmZXJlbmNpYXMgZW50cmUgbGFzIG1lZGlhcyBkZWwgSU1DIGRlIGxvcyBncnVwb3MgIkZ1bWEgPSBzw60iIHkgIkZ1bWEgPSBubyIuCi0gSDEgLT4gSGF5IGRpZmVyZW5jaWFzIGVudHJlIGxhcyBtZWRpYXMgZGUgbG9zIGRvcyBncnVwb3MuCgotIFRhbWHDsW8gZGUgbGEgbXVlc3RyYTogNjY3Ci0gTml2ZWwgZGUgU2lnbmlmaWNhbmNpYTogMC4wNQo6OjoKCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CjIpIEV2YWx1YW1vcyBsYSBpbmRlcGVuZGVuY2lhIGRlIGxhcyBtdWVzdHJhcy4KQ29uc2lkZXJhbmRvIHF1ZToKLSBTb24gZG9zIGdydXBvcyB0b3RhbG1lbnRlIGRpc3RpbnRvcyAoRnVtYT1TaSB5IEZ1bWE9Tm8pIHkgdW4gY2FzbyBkZWwgZ3J1cG8gQSBubyBwdWVkZSBleGlzdGlyIGVuIGVsIGdydXBvIEIuCi0gTGEgb2JzZXJ2YWNpw7NuIGRlbCBHcnVwbyBBIG5vIHB1ZWRlIGluZmVyaXIgZW4gbGEgb2JzZXJ2YWNpw7NuIGRlbCBHcnVwbyBCLgotIE5vIGhheSBuaW5ndW5hIHJlbGFjacOzbiBhcGFyZW50ZSBlbnRyZSBhbWJvcyBncnVwb3MuCgpTZSBjb25zaWRlcmFuIGRvcyBtdWVzdHJhcyBpbmRlcGVuZGllbnRlcy4KOjo6Cgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CjMpIEV2YWx1YW1vcyBub3JtYWxpZGFkLiBTZSBjb25zaWRlcmFuIGxhcyBzaWd1aWVudGVzIGhpcMOzdGVzaXMgPj4gSDA6IHggZXMgbm9ybWFsICYgSDE6IHggbm8gZXMgbm9ybWFsCjo6OgoKYGBge3J9CiMgVmVyaWZpY2Ftb3MgbWVkaWFudGUgdW4gUVFQbG90CmdwbG90IDwtIGRhdG9zICU+JQogIGdncGxvdChhZXMoc2FtcGxlID0gSU1DLCBjb2xvciA9IEZ1bWEpKSArCiAgZ2VvbV9xcSgpICsgZ2VvbV9xcV9saW5lKCkgKwogIGZhY2V0X3dyYXAofiBGdW1hKSArIAogIGdndGl0bGUoIlFRLXBsb3QgZGUgSU1DIHBvciBlc3RhZG8gZGUgZnVtYWRvciIpICsKICB0aGVtZV9idygpCgpnZ3Bsb3RseShncGxvdCkKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkFwYXJlbnRlbWVudGUgYW1iYXMgbXVlc3RyYXMgc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4KClZlcmlmaWNhbW9zIGNvbiB1bmEgZnVuY2nDs24gZXN0YWTDrXN0aWNhICh1c2Ftb3MgTGlsbGllZm9ycyBwb3JxdWUgZWwgdGFtYcOxbyBkZSBsYSBtdWVzdHJhIGVzIG1heW9yIGEgNTApCjo6OgoKYGBge3J9CmJ5KGRhdGEgPSBkYXRvcywgSU5ESUNFUyA9IGRhdG9zJEZ1bWEsIEZVTiA9IGZ1bmN0aW9uKHgpIHsgbGlsbGllLnRlc3QoeCRJTUMpIH0pCmBgYAoKOjo6IHtzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5OyBjb2xvcjogYmxhY2sifQpwLXZhbHVlID49IDAuMDUgZW4gYW1ib3MgZ3J1cG9zOiBOTyBoYXkgZXZpZGVuY2lhIGVzdGFkw61zdGljYSBwYXJhIHJlY2hhemFyIEgwLCBsbyBxdWUgaW5kaWNhIHF1ZSBzZSBwdWVkZSBzdXBvbmVyIHF1ZSBsb3MgZGF0b3MgZGUgbGEgdmFyaWFibGUgSU1DIHNpZ3VlbiB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwuCgo0KSBFdmFsdWFtb3MgaG9tb2dlbmVpZGFkIGRlIHZhcmlhbnphcy4gU2UgY29uc2lkZXJhbiBsYXMgc2lndWllbnRlcyBoaXDDs3Rlc2lzID4+IEgwOiBIYXkgaG9tb2dlbmVpZGFkIGRlIHZhcmlhbnphcyAmIEgxOiBObyBoYXkgaG9tb2dlbmVpZGFkIAo6OjoKCmBgYHtyfQpiYXJ0bGV0dC50ZXN0KElNQyB+IEZ1bWEsIGRhdGE9ZGF0b3MpCmxldmVuZVRlc3QoSU1DIH4gRnVtYSwgZGF0YT1kYXRvcykgIyBTZSB1c2EgY3VhbmRvIG5vIHNlIHB1ZWRlIGFzZWd1cmFyIGxhIG5vcm1hbGlkYWQKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkVuIGFtYm9zIHRlc3RzIHNlIG9ic2VydmEgdW4gcC12YWx1ZSBhbGVqYWRvIGRlbCAwLjA1LCBwb3IgbG8gY3VhbCBubyBoYXkgZXZpZGVuY2lhIHBhcmEgcmVjaGF6YXIgSDAsIGxvIHF1ZSBwZXJtaXRlIHN1cG9uZXIgcXVlIGhheSBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzLgoKNSkgU2VsZWNjaW9uYW1vcyBlbCBlc3RhZMOtc3RpY28gZGUgcHJ1ZWJhIHNlZ8O6biAyKSwgMykgeSA0KSB5IGhhY2Vtb3MgbGEgY29tcGFyYWNpw7NuCgpDb21vIGxhcyBtdWVzdHJhcyBzZSBzdXBvbmVuIGNvbiBkaXN0cmlidWNpw7NuIG5vcm1hbCB5IGxhcyB2YXJpYW56YXMgaG9tb2fDqW5lYXMsIHNlIHV0aWxpemFyw6EgZWwgdC50ZXN0IHBhcmEgaGFjZXIgbGEgcHJ1ZWJhIGRlIGhpcMOzdGVzaXMuCjo6OgoKYGBge3J9CnQudGVzdChJTUMgfiBGdW1hLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCBtdSA9IDAsIHZhci5lcXVhbCA9IFRSVUUsIGRhdGE9ZGF0b3MpICMgcC12YWx1ZSA9IDAuMjA1NQpgYGAKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KQ29tbyBzZSBwdWVkZW4gY29uc2lkZXJhciBhbWJhcyBtdWVzdHJhcyBjb24gZGlzdHJpYnVjacOzbiBub3JtYWwsIGluZGVwZW5kaWVudGVzIHkgY29uIHZhcmlhbnphcyBob21vZ8OpbmVhcywgc2UgcmVhbGl6w7MgdW4gdGVzdCB0IGRlIFN0dWRlbnQgcGFyYSBjb21wYXJhciBsYXMgbWVkaWFzIGRlIElNQyBkZSBsb3MgZ3J1cG9zICJObyBmdW1hZG9yZXMiIHkgIkZ1bWFkb3JlcyIuCgpDb21vIGVsIHAtdmFsb3IgZXN0w6EgYWxlamFkbyB5IG1heW9yIGRlbCAwLDA1IE5PIGhheSBldmlkZW5jaWEgc3VmaWNpZW50ZSBwYXJhIHJlY2hhemFyIEgwLCBsbyBxdWUgcHJlc3Vwb25lIHF1ZSBubyBleGlzdGUgdW5hICBkaWZlcmVuY2lhIHNpZ25pZmljYXRpdmEgZW4gbGEgdmFyaWFjacOzbiBkZWwgcHJvbWVkaW8gZGVsIElNQyBlbnRyZSBhbWJvcyBncnVwb3MgZGUgbGEgcG9ibGFjacOzbi4KOjo6Cgo8YnI+CgojIyMgYi4gUmVhbGl6YXIgcHJ1ZWJhcyBkZSBjb21wYXJhY2nDs24gZGUgbWVkaWFzIHBhcmEgbGEgdmFyaWFibGUgaW5ncmVzbyBzZWfDum4gZ8OpbmVyby4gU2kgY29uc2lkZXJhIHF1ZSBoYXkgYWxndW5hIGhpcMOzdGVzaXMgZGUgaW50ZXLDqXMgYSBwcm9iYXIsIHNlZ8O6biBsbyBvYnNlcnZhZG8gZW4gbGEgUGFydGUgMSwgcmVhbGl6YXIgZWwgdGVzdCBjb3JyZXNwb25kaWVudGUKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KMSkgUGxhbnRlYW1vcyBsYXMgaGlww7N0ZXNpcwotIEhvIC0+IE5vIGhheSBkaWZlcmVuY2lhcyBlbnRyZSBsYXMgbWVkaWFzIGRlbCBpbmdyZXNvIGRlIGxvcyBncnVwb3MgIkdlbmVybyA9IGZlbWVuaW5vIiB5ICJHZW5lcm8gPSBtYXNjdWxpbm8iLgotIEgxIC0+IEhheSBkaWZlcmVuY2lhcyBlbnRyZSBsYXMgbWVkaWFzIGRlIGxvcyBkb3MgZ3J1cG9zLgoKLSBUYW1hw7FvIGRlIGxhIG11ZXN0cmE6IDY2NwotIE5pdmVsIGRlIFNpZ25pZmljYW5jaWE6IDAuMDUKOjo6CgoKOjo6IHtzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5OyBjb2xvcjogYmxhY2sifQoyKSBFdmFsdWFtb3MgbGEgaW5kZXBlbmRlbmNpYSBkZSBsYXMgbXVlc3RyYXMuCkNvbnNpZGVyYW5kbyBxdWU6Ci0gU29uIGRvcyBncnVwb3MgdG90YWxtZW50ZSBkaXN0aW50b3MgKEdlbmVybyA9ICJmZW1lbmlubyIgeSBHZW5lcm8gPSAibWFzY3VsaW5vIikgeSB1biBjYXNvIGRlbCBncnVwbyBBIG5vIHB1ZWRlIGV4aXN0aXIgZW4gZWwgZ3J1cG8gQi4KLSBMYSBvYnNlcnZhY2nDs24gZGVsIEdydXBvIEEgbm8gcHVlZGUgaW5mZXJpciBlbiBsYSBvYnNlcnZhY2nDs24gZGVsIEdydXBvIEIuCi0gTm8gaGF5IG5pbmd1bmEgcmVsYWNpw7NuIGFwYXJlbnRlIGVudHJlIGFtYm9zIGdydXBvcy4KClNlIGNvbnNpZGVyYW4gZG9zIG11ZXN0cmFzIGluZGVwZW5kaWVudGVzLgo6OjoKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KMykgRXZhbHVhbW9zIG5vcm1hbGlkYWQuIFNlIGNvbnNpZGVyYW4gbGFzIHNpZ3VpZW50ZXMgaGlww7N0ZXNpcyA+PiBIMDogeCBlcyBub3JtYWwgJiBIMTogeCBubyBlcyBub3JtYWwKOjo6CgpgYGB7cn0KIyBWZXJpZmljYW1vcyBtZWRpYW50ZSB1biBRUVBsb3QKZ3Bsb3QgPC0gZGF0b3MgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSBpbmdyZXNvLCBjb2xvciA9IEdlbmVybykpICsKICBnZW9tX3FxKCkgKyBnZW9tX3FxX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+IEdlbmVybykgKyAKICBnZ3RpdGxlKCJRUS1wbG90IGRlIGluZ3Jlc28gcG9yIEfDqW5lcm8iKSArCiAgdGhlbWVfYncoKQoKZ2dwbG90bHkoZ3Bsb3QpCmBgYAoKOjo6IHtzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5OyBjb2xvcjogYmxhY2sifQpBcGFyZW50ZW1lbnRlIGFtYmFzIG11ZXN0cmFzIHNpZ3VlbiB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwuCgpWZXJpZmljYW1vcyBjb24gdW5hIGZ1bmNpw7NuIGVzdGFkw61zdGljYSAodXNhbW9zIExpbGxpZWZvcnMgcG9ycXVlIGVsIHRhbWHDsW8gZGUgbGEgbXVlc3RyYSBlcyBtYXlvciBhIDUwKQo6OjoKCmBgYHtyfQpieShkYXRhID0gZGF0b3MsIElORElDRVMgPSBkYXRvcyRHZW5lcm8sIEZVTiA9IGZ1bmN0aW9uKHgpIHsgbGlsbGllLnRlc3QoeCRpbmdyZXNvKSB9KQpgYGAKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KcC12YWx1ZSA+PSAwLjA1IGVuIGFtYm9zIGdydXBvczogTk8gaGF5IGV2aWRlbmNpYSBlc3RhZMOtc3RpY2EgcGFyYSByZWNoYXphciBIMCwgbG8gcXVlIGluZGljYSBxdWUgc2UgcHVlZGUgc3Vwb25lciBxdWUgbG9zIGRhdG9zIGRlIGxhIHZhcmlhYmxlIGluZ3Jlc28gc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbCBjdWFuZG8gbGEgYWdydXBhbW9zIHBvciBHZW5lcm8KCjQpIEV2YWx1YW1vcyBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzLiBTZSBjb25zaWRlcmFuIGxhcyBzaWd1aWVudGVzIGhpcMOzdGVzaXMgPj4gSDA6IEhheSBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzICYgSDE6IE5vIGhheSBob21vZ2VuZWlkYWQgCjo6OgoKYGBge3J9CmJhcnRsZXR0LnRlc3QoaW5ncmVzbyB+IEdlbmVybywgZGF0YT1kYXRvcykKbGV2ZW5lVGVzdChpbmdyZXNvIH4gR2VuZXJvLCBkYXRhPWRhdG9zKSAjIFNlIHVzYSBjdWFuZG8gbm8gc2UgcHVlZGUgYXNlZ3VyYXIgbGEgbm9ybWFsaWRhZApgYGAKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KRW4gYW1ib3MgdGVzdHMgc2Ugb2JzZXJ2YSB1biBwLXZhbHVlIG1lbm9yIGFsIDAuMDUsIHBvciBsbyBjdWFsIHNlIHJlY2hhemEgSDAsIHF1ZSBzZSBpbnRlcnByZXRhIHF1ZSBsYXMgdmFyaWFuemFzIG5vIHNvbiBob21vZ8OpbmVhcy4KCjUpIFNlbGVjY2lvbmFtb3MgZWwgZXN0YWTDrXN0aWNvIGRlIHBydWViYSBzZWfDum4gMiksIDMpIHkgNCkgeSBoYWNlbW9zIGxhIGNvbXBhcmFjacOzbgoKQ29tbyBsYXMgbXVlc3RyYXMgc2Ugc3Vwb25lbiBjb24gZGlzdHJpYnVjacOzbiBub3JtYWwgeSBsYXMgdmFyaWFuemFzIGhldGVyb2fDqW5hcywgc2UgdXRpbGl6YXLDoSBlbCB0ZXN0IGRlIFdlbGNoIHBhcmEgaGFjZXIgbGEgcHJ1ZWJhIGRlIGhpcMOzdGVzaXMuCjo6OgoKYGBge3J9Cm9uZXdheS50ZXN0KGluZ3Jlc28gfiBHZW5lcm8sIGRhdGE9ZGF0b3MpCnQudGVzdChpbmdyZXNvIH4gR2VuZXJvLCBhbHRlcm5hdGl2ZSA9ICJ0d28uc2lkZWQiLCBtdSA9IDAsIHZhci5lcXVhbCA9IEZBTFNFLCBkYXRhPWRhdG9zKQpgYGAKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KRW4gYW1ib3MgdGVzdCBzZSBvYnR1dm8gdW4gcC12YWxvciBtdXkgcGVxdWXDsW8gbG8gcXVlIGluZGljYSBxdWUgc2UgcmVjaGF6YSBIMCwgcG9yIGxvIHRhbnRvIHNlIHB1ZWRlIGRlY2lyIHF1ZSwgZXN0YWTDrXN0aWNhbWVudGUsIGxhIG1lZGlhIHBvYmxhY2lvbmFsIGRlIGluZ3Jlc29zIGVudHJlIGFtYm9zIGfDqW5lcm9zIGVzIGRpZmVyZW50ZS4KOjo6Cgo8YnI+CgpgYGB7cn0KdC50ZXN0KGluZ3Jlc28gfiBHZW5lcm8sIGFsdGVybmF0aXZlID0gImdyZWF0ZXIiLCBtdSA9IDAsIHZhci5lcXVhbCA9IEZBTFNFLCBkYXRhPWRhdG9zKQpgYGAKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KQ29uY2x1c2nDs246IFNlIHB1ZWRlIG9ic2VydmFyIHF1ZSBlbCBwLXZhbG9yID0gMSBwb3IgbG8gcXVlIHNlIE5PIHNlIHJlY2hhemEgbGEgSGlww7N0ZXNpcyBOdWxhLCBjb25maXJtYW5kbyBlc3RhZMOtc3RpY2FtZW50ZSBxdWUgbGEgbWVkaWEgcG9ibGFjaW9uYWwgZGUgaW5ncmVzb3MgZGVsIGfDqW5lcm8gbWFzY3VsaW5vIGVzIG1heW9yIGEgbGEgbWVkaWEgZGUgaW5ncmVzb3MgZGVsIGdlbmVybyBmZW1lbmluby4KOjo6Cgo8YnI+CgoKIyMjIGMuIFJlYWxpemFyIHBydWViYXMgZGUgY29tcGFyYWNpw7NuIGRlIG1lZGlhcyBwYXJhIGxhcyB2YXJpYWJsZXMgSU1DLCBpbmdyZXNvIHkgcHJlbWlvIHNlZ8O6biBSZWdpw7NuCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CjEpIFBsYW50ZWFtb3MgbGFzIGhpcMOzdGVzaXMgZW4gZm9ybWEgZ2VuZXJhbAotIEhvIC0+IE5vIGhheSBkaWZlcmVuY2lhcyBlbnRyZSBsYXMgbWVkaWFzIGRlIElNQywgaW5ncmVzbyB5IHByZW1pbyBwb3IgUmVnaW9uLgotIEgxIC0+IEhheSBhbGd1bmEgbWVkaWEgZGlmZXJlbnRlIGVudHJlIGxhcyByZWdpb25lcy4KCi0gVGFtYcOxbyBkZSBsYSBtdWVzdHJhOiA2NjcKLSBOaXZlbCBkZSBTaWduaWZpY2FuY2lhOiAwLjA1Cjo6OgoKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KMikgRXZhbHVhbW9zIGxhIGluZGVwZW5kZW5jaWEgZGUgbGFzIG11ZXN0cmFzLgpDb25zaWRlcmFuZG8gcXVlOgotIFNvbiBjdWF0cm8gZ3J1cG9zIHRvdGFsbWVudGUgZGlzdGludG9zIHkgdW4gY2FzbyBkZSB1biBncnVwbyBubyBwdWVkZSBleGlzdGlyIGVuIGxvcyBvdHJvcy4KLSBMYSBvYnNlcnZhY2nDs24gZGUgdW4gZ3J1cG8gbm8gcHVlZGUgaW5mZXJpciBlbiBsYSBvYnNlcnZhY2nDs24gZGUgb3Ryb3MuCi0gTm8gaGF5IG5pbmd1bmEgcmVsYWNpw7NuIGFwYXJlbnRlIGVudHJlIGxvcyBncnVwb3MuCgpTZSBjb25zaWRlcmFuIGN1YXRybyBtdWVzdHJhcyBpbmRlcGVuZGllbnRlcy4KOjo6Cgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CioqQWhvcmEgdmFtb3MgYSBhbmFsaXphciBJTUMgcG9yIFJlZ2nDs24qKgoKMykgRXZhbHVhbW9zIG5vcm1hbGlkYWQuIFNlIGNvbnNpZGVyYW4gbGFzIHNpZ3VpZW50ZXMgaGlww7N0ZXNpcyA+PiBIMDogeCBlcyBub3JtYWwgJiBIMTogeCBubyBlcyBub3JtYWwKOjo6CgpgYGB7cn0KIyBWZXJpZmljYW1vcyBtZWRpYW50ZSB1biBRUVBsb3QKZ3Bsb3QgPC0gZGF0b3MgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSBJTUMsIGNvbG9yID0gUmVnaW9uKSkgKwogIGdlb21fcXEoKSArIGdlb21fcXFfbGluZSgpICsKICBmYWNldF93cmFwKH4gUmVnaW9uKSArIAogIGdndGl0bGUoIlFRLXBsb3QgZGUgSU1DIHBvciBSZWdpw7NuIikgKwogIHRoZW1lX2J3KCkKCmdncGxvdGx5KGdwbG90KQpgYGAKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KQXBhcmVudGVtZW50ZSBsYXMgbXVlc3RyYXMgc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4KClZlcmlmaWNhbW9zIGNvbiB1bmEgZnVuY2nDs24gZXN0YWTDrXN0aWNhICh1c2Ftb3MgTGlsbGllZm9ycyBwb3JxdWUgZWwgdGFtYcOxbyBkZSBsYSBtdWVzdHJhIGVzIG1heW9yIGEgNTApCjo6OgoKYGBge3J9CmJ5KGRhdGEgPSBkYXRvcywgSU5ESUNFUyA9IGRhdG9zJFJlZ2lvbiwgRlVOID0gZnVuY3Rpb24oeCkgeyBsaWxsaWUudGVzdCh4JElNQykgfSkKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CnAtdmFsdWUgPj0gMC4wNSBlbiBsb3MgY3VhdHJvIGdydXBvczogTk8gaGF5IGV2aWRlbmNpYSBlc3RhZMOtc3RpY2EgcGFyYSByZWNoYXphciBIMCwgbG8gcXVlIGluZGljYSBxdWUgc2UgcHVlZGUgc3Vwb25lciBxdWUgbG9zIGRhdG9zIGRlIGxhIHZhcmlhYmxlIElNQyBzaWd1ZW4gdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIGN1YW5kbyBsYSBhZ3J1cGFtb3MgcG9yIFJlZ2nDs24KCjQpIEV2YWx1YW1vcyBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzLiBTZSBjb25zaWRlcmFuIGxhcyBzaWd1aWVudGVzIGhpcMOzdGVzaXMgPj4gSDA6IEhheSBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzICYgSDE6IE5vIGhheSBob21vZ2VuZWlkYWQgCjo6OgoKYGBge3J9CmJhcnRsZXR0LnRlc3QoSU1DIH4gUmVnaW9uLCBkYXRhPWRhdG9zKQpsZXZlbmVUZXN0KElNQyB+IFJlZ2lvbiwgZGF0YT1kYXRvcykgIyBTZSB1c2EgY3VhbmRvIG5vIHNlIHB1ZWRlIGFzZWd1cmFyIGxhIG5vcm1hbGlkYWQKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkVuIGFtYm9zIHRlc3RzIHNlIG9ic2VydmEgdW4gcC12YWx1ZSBtZW5vciBhbCAwLjA1LCBwb3IgbG8gY3VhbCBzZSByZWNoYXphIEgwLCBwb3IgbG8gcXVlIHNlIGludGVycHJldGEgcXVlIGxhcyB2YXJpYW56YXMgbm8gc29uIGhvbW9nw6luZWFzLgoKNSkgU2VsZWNjaW9uYW1vcyBlbCBlc3RhZMOtc3RpY28gZGUgcHJ1ZWJhIHNlZ8O6biAyKSwgMykgeSA0KSB5IGhhY2Vtb3MgbGEgY29tcGFyYWNpw7NuCgpDb21vIGxhcyBtdWVzdHJhcyBzZSBzdXBvbmVuIGNvbiBkaXN0cmlidWNpw7NuIG5vcm1hbCB5IGxhcyB2YXJpYW56YXMgaGV0ZXJvZ8OpbmFzLCBzZSB1dGlsaXphcsOhIGVsIHRlc3QgZGUgV2VsY2ggcGFyYSBoYWNlciBsYSBwcnVlYmEgZGUgaGlww7N0ZXNpcy4KOjo6CgpgYGB7cn0Kb25ld2F5LnRlc3QoSU1DIH4gUmVnaW9uLCBkYXRhPWRhdG9zKQprcnVza2FsLnRlc3QoSU1DIH4gUmVnaW9uLCBkYXRhID0gZGF0b3MpCmBgYAoKOjo6IHtzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5OyBjb2xvcjogYmxhY2sifQpFbiBhbWJvcyB0ZXN0cyBzZSBvYnR1dm8gdW4gcC12YWxvciBtdXkgcGVxdWXDsW8gbG8gcXVlIGluZGljYSBxdWUgc2UgcmVjaGF6YSBIMCwgcG9yIGxvIHRhbnRvIHNlIHB1ZWRlIGRlY2lyIHF1ZSwgZXN0YWTDrXN0aWNhbWVudGUsIGxhIG1lZGlhIHBvYmxhY2lvbmFsIGRlIElNQyBlbnRyZSBsYXMgcmVnaW9uZXMgZXMgZGlmZXJlbnRlLgoKU2UgdmEgYSB1dGlsaXphciB1bmEgZnVuY2nDs24gcGFyYSBldmFsdWFyIGRlIGEgcGFyZXMgZGUgcmVnaW9uZXMgbGFzIG1lZGlhcyBkZSBJTUMsIGEgZmluIGRlIGlkZW50aWZpY2FyIGN1YWxlcyBzb24gbGFzIG1lZGlhcyBxdWUgZGlmaWVyZW4uIAo6OjoKCjxicj4KCmBgYHtyfQpjb21wYXJhcl9kb3NfcmVnaW9uZXMgPSBmdW5jdGlvbihkcywgbm9tYnJlX3ZhcmlhYmxlKXsKICByZWdpb25lc191bmljYXMgPSBkcyAlPiUgZGlzdGluY3QoUmVnaW9uKQogIGxzdCA9IGFzLmxpc3QoYXMuZGF0YS5mcmFtZSh0KHJlZ2lvbmVzX3VuaWNhcykpKQogIAogIHB2YWxvcmVzX2RzID0gZGF0YS5mcmFtZSh2YXJpYWJsZXMgPSBjaGFyYWN0ZXIoKSwgcF92YWxvcj1jaGFyYWN0ZXIoKSkKICAKICBmb3JtdWxhX3N0ciA8LSByZWZvcm11bGF0ZSgiUmVnaW9uIiwgbm9tYnJlX3ZhcmlhYmxlKQogIAogIHdoaWxlKGxlbmd0aChsc3QpPjEpewogICAgcmVnaW9uX0EgPSBhcy5jaGFyYWN0ZXIobHN0WzFdKQogICAgCiAgICBsc3QgPSBsc3RbLTFdCiAgICAKICAgIGZvcihyZWdpb25fQiBpbiBsc3QpewogICAgICByZWdpb25fQiA9IGFzLmNoYXJhY3RlcihyZWdpb25fQikKICAgICAgCiAgICAgIHdvcmtpbmdfZHMgPSBkcyAlPiUgZmlsdGVyKFJlZ2lvbiAlaW4lIGMocmVnaW9uX0EsIHJlZ2lvbl9CKSkKICAgICAgCiAgICAgIHJkbyA9IHQudGVzdChmb3JtdWxhX3N0ciwgYWx0ZXJuYXRpdmUgPSAidHdvLnNpZGVkIiwgbXUgPSAwLCB2YXIuZXF1YWwgPSBGQUxTRSwgZGF0YT13b3JraW5nX2RzKQogICAgICAKICAgICAgbGFiZWwgPSBwYXN0ZTAocmVnaW9uX0EsIi0iLHJlZ2lvbl9CKQpwdmFsb3Jlc19kcyA9IHB2YWxvcmVzX2RzICU+JSB1bmlvbihkYXRhLmZyYW1lKHZhcmlhYmxlcz1sYWJlbCwgcF92YWxvcj1hcy5jaGFyYWN0ZXIocmRvW1sicC52YWx1ZSJdXSkpKQogICAgfQogIH0KCiAgcmV0dXJuKHB2YWxvcmVzX2RzKQp9CgpkdCA9IGNvbXBhcmFyX2Rvc19yZWdpb25lcyhkYXRvcywgIklNQyIpCmthYmxlKGR0LCBjYXB0aW9uPSI8Y2VudGVyPjxiPlJlc3VsdGFkbyBUZXN0IHQgZGUgU3R1ZGVudCAocC12YWxvcikgLSBJTUMgY2FkYSAyIFJlZ2lvbmVzPC9iPjwvY2VudGVyPiIpCiAgCmBgYAoKOjo6IHtzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5OyBjb2xvcjogYmxhY2sifQpEZSBhY3VlcmRvIGFsIHRlc3QgdCBkZSBTdHVkZW50LCB0b2RvcyB0aWVuZW4gbG9zIHAtdmFsb3JlcyBtdXkgY2VyY2Fub3MgYSAwLCBwb3IgbG8gcXVlIHNlIHJlY2hhemEgSDAgZW4gdG9kb3MgbG9zIGNhc29zIGV4Y2VwdG8gcGFyYSBlbCBwYXIgZGUgcmVnaW9uZXMgIm5vcmRlc3RlLW5vcm9lc3RlIi4KCkFuYWxpemFuZG8gZWwgcGFyICJub3JkZXN0ZS1ub3JvZXN0ZSIgc2UgcHVlZGUgb2JzZXJ2YXIgcXVlIGVsIHAtdmFsb3IgZXMgMC41MzczLCBtdXkgYWx0bywgcG9yIGxvIHF1ZSBubyBoYXkgZXZpZGVuY2lhIHBhcmEgcmVjaGF6YXIgSDAgeSBzZSBwb2RyaWEgY29udGVtcGxhciBxdWUgZXN0YWTDrXN0aWNhbWVudGUgbGEgbWVkaWEgZGUgSU1DIGRlIGFtYmFzIHBvYmxhY2lvbmVzIHNvbiBpZ3VhbGVzLgo6OjoKCjxicj4KCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KKipBaG9yYSB2YW1vcyBhIGFuYWxpemFyIGluZ3Jlc28gcG9yIFJlZ2nDs24qKgoKMykgRXZhbHVhbW9zIG5vcm1hbGlkYWQuIFNlIGNvbnNpZGVyYW4gbGFzIHNpZ3VpZW50ZXMgaGlww7N0ZXNpcyA+PiBIMDogeCBlcyBub3JtYWwgJiBIMTogeCBubyBlcyBub3JtYWwKOjo6CgpgYGB7cn0KIyBWZXJpZmljYW1vcyBtZWRpYW50ZSB1biBRUVBsb3QKZ3Bsb3QgPC0gZGF0b3MgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSBpbmdyZXNvLCBjb2xvciA9IFJlZ2lvbikpICsKICBnZW9tX3FxKCkgKyBnZW9tX3FxX2xpbmUoKSArCiAgZmFjZXRfd3JhcCh+IFJlZ2lvbikgKyAKICBnZ3RpdGxlKCJRUS1wbG90IGRlIGluZ3Jlc28gcG9yIFJlZ2nDs24iKSArCiAgdGhlbWVfYncoKQoKZ2dwbG90bHkoZ3Bsb3QpCmBgYAoKOjo6IHtzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjogbGlnaHRncmF5OyBjb2xvcjogYmxhY2sifQpBcGFyZW50ZW1lbnRlIGxhcyBtdWVzdHJhcyBzaWd1ZW4gdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsLgoKVmVyaWZpY2Ftb3MgY29uIHVuYSBmdW5jacOzbiBlc3RhZMOtc3RpY2EgKHVzYW1vcyBMaWxsaWVmb3JzIHBvcnF1ZSBlbCB0YW1hw7FvIGRlIGxhIG11ZXN0cmEgZXMgbWF5b3IgYSA1MCkKOjo6CgpgYGB7cn0KYnkoZGF0YSA9IGRhdG9zLCBJTkRJQ0VTID0gZGF0b3MkUmVnaW9uLCBGVU4gPSBmdW5jdGlvbih4KSB7IGxpbGxpZS50ZXN0KHgkaW5ncmVzbykgfSkKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CnAtdmFsdWUgPj0gMC4wNSBlbiBsb3MgY3VhdHJvIGdydXBvczogTk8gaGF5IGV2aWRlbmNpYSBlc3RhZMOtc3RpY2EgcGFyYSByZWNoYXphciBIMCwgbG8gcXVlIGluZGljYSBxdWUgc2UgcHVlZGUgc3Vwb25lciBxdWUgbG9zIGRhdG9zIGRlIGxhIHZhcmlhYmxlIGluZ3Jlc28gc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbCBjdWFuZG8gbGEgYWdydXBhbW9zIHBvciBSZWdpw7NuCgo0KSBFdmFsdWFtb3MgaG9tb2dlbmVpZGFkIGRlIHZhcmlhbnphcy4gU2UgY29uc2lkZXJhbiBsYXMgc2lndWllbnRlcyBoaXDDs3Rlc2lzID4+IEgwOiBIYXkgaG9tb2dlbmVpZGFkIGRlIHZhcmlhbnphcyAmIEgxOiBObyBoYXkgaG9tb2dlbmVpZGFkIAo6OjoKCmBgYHtyfQpiYXJ0bGV0dC50ZXN0KGluZ3Jlc28gfiBSZWdpb24sIGRhdGE9ZGF0b3MpCmxldmVuZVRlc3QoaW5ncmVzbyB+IFJlZ2lvbiwgZGF0YT1kYXRvcykgIyBTZSB1c2EgY3VhbmRvIG5vIHNlIHB1ZWRlIGFzZWd1cmFyIGxhIG5vcm1hbGlkYWQKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkVuIGFtYm9zIHRlc3RzIHNlIG9ic2VydmEgdW4gcC12YWx1ZSBtZW5vciBhbCAwLjA1LCBwb3IgbG8gY3VhbCBzZSByZWNoYXphIEgwLCBwb3IgbG8gcXVlIHNlIGludGVycHJldGEgcXVlIGxhcyB2YXJpYW56YXMgbm8gc29uIGhvbW9nw6luZWFzLgoKNSkgU2VsZWNjaW9uYW1vcyBlbCBlc3RhZMOtc3RpY28gZGUgcHJ1ZWJhIHNlZ8O6biAyKSwgMykgeSA0KSB5IGhhY2Vtb3MgbGEgY29tcGFyYWNpw7NuCgpDb21vIGxhcyBtdWVzdHJhcyBzZSBzdXBvbmVuIGNvbiBkaXN0cmlidWNpw7NuIG5vcm1hbCB5IGxhcyB2YXJpYW56YXMgaGV0ZXJvZ8OpbmFzLCBzZSB1dGlsaXphcsOhIGVsIHRlc3QgZGUgV2VsY2ggcGFyYSBoYWNlciBsYSBwcnVlYmEgZGUgaGlww7N0ZXNpcy4KOjo6CgpgYGB7cn0Kb25ld2F5LnRlc3QoaW5ncmVzbyB+IFJlZ2lvbiwgZGF0YT1kYXRvcykKa3J1c2thbC50ZXN0KGluZ3Jlc28gfiBSZWdpb24sIGRhdGEgPSBkYXRvcykKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkVuIGFtYm9zIHRlc3RzIHNlIG9idHV2byB1biBwLXZhbG9yID4gMC4wNSBsbyBxdWUgaW5kaWNhIHF1ZSBOTyBoYXkgZXZpZGVuY2lhIHBhcmEgcmVjaGF6YXIgSDAsIHBvciBsbyB0YW50byBzZSBwdWVkZSBkZWNpciBxdWUsIGVzdGFkw61zdGljYW1lbnRlLCBsYSBtZWRpYSBwb2JsYWNpb25hbCBkZSBpbmdyZXNvIGVudHJlIGxhcyByZWdpb25lcyBlcyBzaW1pbGFyLgoKU2UgdmEgYSB1dGlsaXphciB1bmEgZnVuY2nDs24gcGFyYSBldmFsdWFyIGRlIGEgcGFyZXMgZGUgcmVnaW9uZXMgbGFzIG1lZGlhcyBkZSBpbmdyZXNvLCBhIGZpbiBkZSBjb3Jyb2JvcmFyIGxhIGNvbmNsdXNpw7NuIGFudGVyaW9yLiAKOjo6Cgo8YnI+CgpgYGB7cn0KZHQgPSBjb21wYXJhcl9kb3NfcmVnaW9uZXMoZGF0b3MsICJpbmdyZXNvIikKa2FibGUoZHQsIGNhcHRpb249IjxjZW50ZXI+PGI+UmVzdWx0YWRvIFRlc3QgdCBkZSBTdHVkZW50IChwLXZhbG9yKSAtIGluZ3Jlc28gY2FkYSAyIFJlZ2lvbmVzPC9iPjwvY2VudGVyPiIpCiAgCmBgYAo8YnI+Cgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CioqQWhvcmEgdmFtb3MgYSBhbmFsaXphciBwcmVtaW8gcG9yIFJlZ2nDs24qKgoKMykgRXZhbHVhbW9zIG5vcm1hbGlkYWQuIFNlIGNvbnNpZGVyYW4gbGFzIHNpZ3VpZW50ZXMgaGlww7N0ZXNpcyA+PiBIMDogeCBlcyBub3JtYWwgJiBIMTogeCBubyBlcyBub3JtYWwKOjo6CgpgYGB7cn0KIyBWZXJpZmljYW1vcyBtZWRpYW50ZSB1biBRUVBsb3QKZ3Bsb3QgPC0gZGF0b3MgJT4lCiAgZ2dwbG90KGFlcyhzYW1wbGUgPSBwcmVtaW8sIGNvbG9yID0gUmVnaW9uKSkgKwogIGdlb21fcXEoKSArIGdlb21fcXFfbGluZSgpICsKICBmYWNldF93cmFwKH4gUmVnaW9uKSArIAogIGdndGl0bGUoIlFRLXBsb3QgZGUgUHJlbWlvIHBvciBSZWdpw7NuIikgKwogIHRoZW1lX2J3KCkKCmdncGxvdGx5KGdwbG90KQpgYGAKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KQXBhcmVudGVtZW50ZSBsYXMgbXVlc3RyYXMgc2lndWVuIHVuYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4KClZlcmlmaWNhbW9zIGNvbiB1bmEgZnVuY2nDs24gZXN0YWTDrXN0aWNhICh1c2Ftb3MgTGlsbGllZm9ycyBwb3JxdWUgZWwgdGFtYcOxbyBkZSBsYSBtdWVzdHJhIGVzIG1heW9yIGEgNTApCjo6OgoKYGBge3J9CmJ5KGRhdGEgPSBkYXRvcywgSU5ESUNFUyA9IGRhdG9zJFJlZ2lvbiwgRlVOID0gZnVuY3Rpb24oeCkgeyBsaWxsaWUudGVzdCh4JHByZW1pbykgfSkKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CnAtdmFsdWUgPj0gMC4wNSBlbiBsb3MgY3VhdHJvIGdydXBvczogTk8gaGF5IGV2aWRlbmNpYSBlc3RhZMOtc3RpY2EgcGFyYSByZWNoYXphciBIMCwgbG8gcXVlIGluZGljYSBxdWUgc2UgcHVlZGUgc3Vwb25lciBxdWUgbG9zIGRhdG9zIGRlIGxhIHZhcmlhYmxlIHByZW1pbyBzaWd1ZW4gdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIGN1YW5kbyBsYSBhZ3J1cGFtb3MgcG9yIFJlZ2nDs24KCjQpIEV2YWx1YW1vcyBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzLiBTZSBjb25zaWRlcmFuIGxhcyBzaWd1aWVudGVzIGhpcMOzdGVzaXMgPj4gSDA6IEhheSBob21vZ2VuZWlkYWQgZGUgdmFyaWFuemFzICYgSDE6IE5vIGhheSBob21vZ2VuZWlkYWQgCjo6OgoKYGBge3J9CmJhcnRsZXR0LnRlc3QocHJlbWlvIH4gUmVnaW9uLCBkYXRhPWRhdG9zKQpsZXZlbmVUZXN0KHByZW1pbyB+IFJlZ2lvbiwgZGF0YT1kYXRvcykgIyBTZSB1c2EgY3VhbmRvIG5vIHNlIHB1ZWRlIGFzZWd1cmFyIGxhIG5vcm1hbGlkYWQKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkVuIGFtYm9zIHRlc3RzIHNlIG9ic2VydmEgdW4gcC12YWx1ZSBtYXlvciBhIDAuMDUsIHBvciBsbyBjdWFsIE5PIGhheSBldmlkZW5jaWEgcGFyYSByZWNoYXphciBIMCwgcG9yIGxvIHF1ZSBzZSBpbnRlcnByZXRhIHF1ZSBsYXMgdmFyaWFuemFzIHNvbiBob21vZ8OpbmVhcy4KCjUpIFNlbGVjY2lvbmFtb3MgZWwgZXN0YWTDrXN0aWNvIGRlIHBydWViYSBzZWfDum4gMiksIDMpIHkgNCkgeSBoYWNlbW9zIGxhIGNvbXBhcmFjacOzbgoKQ29tbyBsYXMgbXVlc3RyYXMgc2Ugc3Vwb25lbiBjb24gZGlzdHJpYnVjacOzbiBub3JtYWwsIGxhcyB2YXJpYW56YXMgc29uIGhvbW9nw6luZWFzIHkgc2UgdHJhdGEgZGUgdmFyaW9zIGdydXBvcywgc2UgdXRpbGl6YXLDoSBlbCB0ZXN0IEFOT1ZBIHBhcmEgaGFjZXIgbGEgcHJ1ZWJhIGRlIGhpcMOzdGVzaXMuCjo6OgoKYGBge3J9CmFub3ZhX3Jlc3VsdCA8LSBhb3YocHJlbWlvIH4gUmVnaW9uLCBkYXRhID0gZGF0b3MpCnN1bW1hcnkoYW5vdmFfcmVzdWx0KQoKb25ld2F5LnRlc3QocHJlbWlvIH4gUmVnaW9uLCBkYXRhPWRhdG9zLCB2YXIuZXF1YWwgPSBUUlVFKSAjIHAtdmFsdWUgPSAwLjkwNQpgYGAKCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KRW4gYW1ib3MgdGVzdHMgc2Ugb2J0dXZvIHVuIHAtdmFsb3IgbXV5IGFsdG8gbG8gcXVlIGluZGljYSBxdWUgaGF5IHVuYSBmdWVydGUgZXZpZGVuY2lhIHBhcmEgTk8gcmVjaGF6YXIgSDAsIHBvciBsbyB0YW50byBzZSBwdWVkZSBkZWNpciBxdWUsIGVzdGFkw61zdGljYW1lbnRlLCBsYSBtZWRpYSBwb2JsYWNpb25hbCBkZSBwcmVtaW8gZW50cmUgbGFzIHJlZ2lvbmVzIGVzIHNpbWlsYXIuCgpTZSB2YSBhIHV0aWxpemFyIHVuYSBmdW5jacOzbiBwYXJhIGV2YWx1YXIgZGUgYSBwYXJlcyBkZSByZWdpb25lcyBsYXMgbWVkaWFzIGRlIHByZW1pbywgYSBmaW4gZGUgY29ycm9ib3JhciBsYSBjb25jbHVzacOzbiBhbnRlcmlvci4gCjo6OgoKPGJyPgoKYGBge3J9CmR0ID0gY29tcGFyYXJfZG9zX3JlZ2lvbmVzKGRhdG9zLCAicHJlbWlvIikKa2FibGUoZHQsIGNhcHRpb249IjxjZW50ZXI+PGI+UmVzdWx0YWRvIFRlc3QgdCBkZSBTdHVkZW50IChwLXZhbG9yKSAtIFByZW1pbyBjYWRhIDIgUmVnaW9uZXM8L2I+PC9jZW50ZXI+IikKYGBgCgo8YnI+Cgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9ClByb2NlZGVtb3MgYSBlamVjdXRhciBkb3MgdGVzdHMgUG9zdC1IT0M6IHRlc3QgZGUgVHVrZXkgeSBCb25mZXJyb25pCjo6OgoKCmBgYHtyfQppbnRlcnZhbG9zID0gVHVrZXlIU0QoYW5vdmFfcmVzdWx0KSAKcGxvdChpbnRlcnZhbG9zKSAKCnBhaXJ3aXNlLnQudGVzdCh4ID0gZGF0b3MkcHJlbWlvLCBnID0gZGF0b3MkUmVnaW9uLCBwLmFkanVzdC5tZXRob2QgPSAiYm9uZmVycm9uaSIsCiAgICAgICAgICAgICAgICBwb29sLnNkID0gVFJVRSwgcGFpcmVkID0gRkFMU0UsIGFsdGVybmF0aXZlID0gInR3by5zaWRlZCIpCmBgYAo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkNvbiBhbWJvcyB0ZXN0cyBjb3Jyb2JvcmFtb3MgbGEgY29uY2x1c2nDs24gZGVsIEFOT1ZBCjo6OgoKPGJyPgoKIyMjIGQuIFByb2JhciBzaSBwdWVkZSBhc3VtaXJzZSBpbmRlcGVuZGVuY2lhIGVudHJlIGxhIHByb2NlZGVuY2lhIChSZWdpw7NuKSB5IGxhIGNvbmRpY2nDs24gZGUgZnVtYWRvciBkZSBsYSBwZXJzb25hCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9ClBhcmEgZXZhbHVhciBkZXBlbmRlbmNpYSB2YW1vcyBhIHJlYWxpemFyIFRhYmxhcyBkZSBDb250aW5nZW5jaWEsIHF1ZSBub3MgcGVybWl0ZW4gZXZhbHVhciBkb3MgdmFyaWFibGVzIGN1YWxpdGF0aXZhcyB5IGJ1c2NhciB1bmEgcmVsYWNpw7NuIGVudHJlIGVsbGFzLgoKQ29tcGFyYW1vcyBsYSB0YWJsYSBkZSBmcmVjdWVuY2lhcyBvYnNlcnZhZGFzIGNvbiBsYSB0YWJsYSBkZSBmcmVjdWVuY2lhcyBlc3BlcmFkYSAoc3Vwb25pZW5kbyBpbmRlcGVuZGVuY2lhKSB1dGlsaXphbmRvIHVuIGVzdGFkw61zdGljbyBkZSBwcnVlYmEuCgoxKSBQbGFudGVhciBsYXMgaGlww7N0ZXNpczoKClNpZW5kbyAgPj4gWCA9IFJlZ2nDs24gJiBZID0gRnVtYQoKLSBIMDogWCBlIFkgc29uIGluZGVwZW5kaWVudGVzLgotIEgxOiBIYXkgYWxndW5hIGRlcGVuZGVuY2lhIGVudHJlIGVsbGFzLgoKMikgQXJtYXJtb3MgbGEgdGFibGEgZGUgZnJlY3VlbmNpYXMKOjo6CgpgYGB7cn0KZnJlY3VlbmNpYXMgPSB0YWJsZShkYXRvcyRSZWdpb24sIGRhdG9zJEZ1bWEpCgptYXJnaW4udGFibGUoZnJlY3VlbmNpYXMsIDEpICAKbWFyZ2luLnRhYmxlKGZyZWN1ZW5jaWFzLCAyKQoKcHJvcC50YWJsZShmcmVjdWVuY2lhcykKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CjMpIEVqZWN1dGFtb3MgbGEgcHJ1ZWJhIGRlIGluZGVwZW5kZW5jaWEsIHV0aWxpemFuZG8gZWwgdGVzdCBjaGkgY3VhZHJhZG8gCjo6OgoKYGBge3J9CmNoaXNxLnRlc3QoZnJlY3VlbmNpYXMsIGNvcnJlY3QgPSBGKQoKYGBgCjo6OiB7c3R5bGU9ImJhY2tncm91bmQtY29sb3I6IGxpZ2h0Z3JheTsgY29sb3I6IGJsYWNrIn0KQ29uY2x1c2nDs246IEVuIGVsIHRlc3QgZGUgQ2hpIGN1YWRyYWRvIHNvYnJlIGxhIHRhYmxhIGRlIGZyZW5jdWVuY2lhcyBzZSBvYnNlcnZhIHVuIHAtdmFsb3IgMC4yNDkxLCBlcyBiYXN0YW50ZSBtYXlvciBhIDAuMDUsIG5vIGhheSBldmlkZW5jaWEgcGFyYSByZWNoYXphciBIMC4KCkVzdG8gaW5kaWNhcsOtYSBxdWUgZXN0YWTDrXN0aWNhbWVudGUgc2UgcHVlZGUgY29uc2lkZXJhciBxdWUgaGF5IGluZGVwZW5kZW5jaWEgZW50cmUgYW1iYXMgdmFyaWFibGVzIGN1YWxpdGF0aXZhczogUmVnaW9uIC0gRnVtYQoKRW50b25jZXMsIE5PIGhheSBldmlkZW5jaWEgc3VmaWNpZW50ZSBwYXJhIGFmaXJtYXIgcXVlIGxhIGNvbmRpY2nDs24gZGUgZnVtYWRvciBkZXBlbmRhIGRlIGxhIHJlZ2nDs24uCgo0KSBDb3Jyb2JvcmFyIG5pdmVsZXMgZGUgYXNvY2lhY2nDs24gbWVkaWFudGUgZWwgQ29lZmljaWVudGUgZGUgQ29udGluZ2VuY2lhIHkgViBkZSBDcmFtZXIKOjo6CgpgYGB7cn0KYXNzb2NzdGF0cyhmcmVjdWVuY2lhcykKYGBgCgo6Ojoge3N0eWxlPSJiYWNrZ3JvdW5kLWNvbG9yOiBsaWdodGdyYXk7IGNvbG9yOiBibGFjayJ9CkNvcnJvYm9yYW5kbyBsb3Mgbml2ZWxlcyBkZSBhc29jaWFjacOzbiBzZSBvYnRpZW5lbiBpbmRpY2VzIG11eSBiYWpvcyBsbyBxdWUgcmVmdWVyemEgbGEgZXZpZGVuY2lhIGRlIGluZGVwZW5kZW5jaWEgb2J0ZW5pZGEgcG9yIGVsIHRlc3QgZGUgQ2hpIGN1YWRyYWRvLgoKKipGSU4qKgo6OjoKCjxicj4=